changeset 11155:1d6534291026

6874779 Solaris igb driver needs to support Intel 82580 Barton Hills 6901478 igb is not lint clean after the integration of CR6708291
author zhefeng xu - Sun Microsystems - Beijing China <Jason.Xu@Sun.COM>
date Mon, 23 Nov 2009 14:27:01 +0800
parents cec14087b5a4
children fa5f12909da7
files usr/src/pkgdefs/SUNWigb/postinstall usr/src/uts/common/io/igb/igb_82575.c usr/src/uts/common/io/igb/igb_82575.h usr/src/uts/common/io/igb/igb_api.c usr/src/uts/common/io/igb/igb_api.h usr/src/uts/common/io/igb/igb_defines.h usr/src/uts/common/io/igb/igb_hw.h usr/src/uts/common/io/igb/igb_mac.c usr/src/uts/common/io/igb/igb_mac.h usr/src/uts/common/io/igb/igb_main.c usr/src/uts/common/io/igb/igb_manage.c usr/src/uts/common/io/igb/igb_manage.h usr/src/uts/common/io/igb/igb_nvm.c usr/src/uts/common/io/igb/igb_nvm.h usr/src/uts/common/io/igb/igb_osdep.h usr/src/uts/common/io/igb/igb_phy.c usr/src/uts/common/io/igb/igb_phy.h usr/src/uts/common/io/igb/igb_regs.h usr/src/uts/common/io/igb/igb_sw.h usr/src/uts/common/io/igb/igb_tx.c
diffstat 20 files changed, 1452 insertions(+), 474 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/pkgdefs/SUNWigb/postinstall	Mon Nov 23 12:45:18 2009 +0800
+++ b/usr/src/pkgdefs/SUNWigb/postinstall	Mon Nov 23 14:27:01 2009 +0800
@@ -135,5 +135,11 @@
 	"pciex8086,10e7"
 	"pciex8086,10e8"
 	"pciex8086,150a"
-	"pciex8086,150d"'	\
+	"pciex8086,150d"
+	"pciex8086,150e"
+	"pciex8086,150f"
+	"pciex8086,1510"
+	"pciex8086,1511"
+	"pciex8086,1516"
+	"pciex8086,1518"'	\
 	-b "$BASEDIR" igb
--- a/usr/src/uts/common/io/igb/igb_82575.c	Mon Nov 23 12:45:18 2009 +0800
+++ b/usr/src/uts/common/io/igb/igb_82575.c	Mon Nov 23 14:27:01 2009 +0800
@@ -26,7 +26,7 @@
  * Use is subject to license terms of the CDDL.
  */
 
-/* IntelVersion: 1.123 v2-9-8_2009-6-12 */
+/* IntelVersion: 1.143 scm_100809_154340 */
 
 /*
  * 82575EB Gigabit Network Connection
@@ -54,16 +54,20 @@
 static s32 e1000_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset,
     u16 *data);
 static s32 e1000_reset_hw_82575(struct e1000_hw *hw);
+static s32 e1000_reset_hw_82580(struct e1000_hw *hw);
+static s32 e1000_read_phy_reg_82580(struct e1000_hw *hw, u32 offset,
+    u16 *data);
+static s32 e1000_write_phy_reg_82580(struct e1000_hw *hw, u32 offset,
+    u16 data);
 static s32 e1000_set_d0_lplu_state_82575(struct e1000_hw *hw,
     bool active);
 static s32 e1000_setup_copper_link_82575(struct e1000_hw *hw);
-static s32 e1000_setup_fiber_serdes_link_82575(struct e1000_hw *hw);
+static s32 e1000_setup_serdes_link_82575(struct e1000_hw *hw);
 static s32 e1000_valid_led_default_82575(struct e1000_hw *hw, u16 *data);
 static s32 e1000_write_phy_reg_sgmii_82575(struct e1000_hw *hw,
     u32 offset, u16 data);
 static void e1000_clear_hw_cntrs_82575(struct e1000_hw *hw);
 static s32 e1000_acquire_swfw_sync_82575(struct e1000_hw *hw, u16 mask);
-static s32 e1000_configure_pcs_link_82575(struct e1000_hw *hw);
 static s32 e1000_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw,
     u16 *speed, u16 *duplex);
 static s32 e1000_get_phy_id_82575(struct e1000_hw *hw);
@@ -72,9 +76,14 @@
 static s32 e1000_reset_init_script_82575(struct e1000_hw *hw);
 static s32 e1000_read_mac_addr_82575(struct e1000_hw *hw);
 static void e1000_power_down_phy_copper_82575(struct e1000_hw *hw);
-void e1000_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw);
+static void e1000_shutdown_serdes_link_82575(struct e1000_hw *hw);
 static s32 e1000_set_pcie_completion_timeout(struct e1000_hw *hw);
 
+static const u16 e1000_82580_rxpbs_table[] =
+	{36, 72, 144, 1, 2, 4, 8, 16, 35, 70, 140};
+#define	E1000_82580_RXPBS_TABLE_SIZE \
+	(sizeof (e1000_82580_rxpbs_table)/sizeof (u16))
+
 /*
  * e1000_init_phy_params_82575 - Init PHY func ptrs.
  * @hw: pointer to the HW structure
@@ -90,11 +99,11 @@
 	if (hw->phy.media_type != e1000_media_type_copper) {
 		phy->type = e1000_phy_none;
 		goto out;
-	} else {
-		phy->ops.power_up = e1000_power_up_phy_copper;
-		phy->ops.power_down = e1000_power_down_phy_copper_82575;
 	}
 
+	phy->ops.power_up = e1000_power_up_phy_copper;
+	phy->ops.power_down = e1000_power_down_phy_copper_82575;
+
 	phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
 	phy->reset_delay_us = 100;
 
@@ -108,6 +117,10 @@
 		phy->ops.reset = e1000_phy_hw_reset_sgmii_82575;
 		phy->ops.read_reg = e1000_read_phy_reg_sgmii_82575;
 		phy->ops.write_reg = e1000_write_phy_reg_sgmii_82575;
+	} else if (hw->mac.type == e1000_82580) {
+		phy->ops.reset = e1000_phy_hw_reset_generic;
+		phy->ops.read_reg = e1000_read_phy_reg_82580;
+		phy->ops.write_reg = e1000_write_phy_reg_82580;
 	} else {
 		phy->ops.reset = e1000_phy_hw_reset_generic;
 		phy->ops.read_reg = e1000_read_phy_reg_igp;
@@ -136,6 +149,14 @@
 		phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_82575;
 		phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_generic;
 		break;
+	case I82580_I_PHY_ID:
+		phy->type = e1000_phy_82580;
+		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;
+		break;
 	default:
 		ret_val = -E1000_ERR_PHY;
 		goto out;
@@ -228,24 +249,33 @@
 	dev_spec->sgmii_active = false;
 
 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
-	if ((ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) ==
-	    E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES) {
+	switch (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) {
+	case E1000_CTRL_EXT_LINK_MODE_SGMII:
+		dev_spec->sgmii_active = true;
+		ctrl_ext |= E1000_CTRL_I2C_ENA;
+		break;
+	case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX:
+	case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES:
 		hw->phy.media_type = e1000_media_type_internal_serdes;
 		ctrl_ext |= E1000_CTRL_I2C_ENA;
-	} else if (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_SGMII) {
-		dev_spec->sgmii_active = true;
-		ctrl_ext |= E1000_CTRL_I2C_ENA;
-	} else {
+		break;
+	default:
 		ctrl_ext &= ~E1000_CTRL_I2C_ENA;
+		break;
 	}
+
 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
 
 	/* Set mta register count */
 	mac->mta_reg_count = 128;
+	/* Set uta register count */
+	mac->uta_reg_count = (hw->mac.type == e1000_82575) ? 0 : 128;
 	/* Set rar entry count */
 	mac->rar_entry_count = E1000_RAR_ENTRIES_82575;
 	if (mac->type == e1000_82576)
 		mac->rar_entry_count = E1000_RAR_ENTRIES_82576;
+	if (mac->type == e1000_82580)
+		mac->rar_entry_count = E1000_RAR_ENTRIES_82580;
 	/* Set if part includes ASF firmware */
 	mac->asf_firmware_present = true;
 	/* Set if manageability features are enabled. */
@@ -258,7 +288,10 @@
 	/* bus type/speed/width */
 	mac->ops.get_bus_info = e1000_get_bus_info_pcie_generic;
 	/* reset */
-	mac->ops.reset_hw = e1000_reset_hw_82575;
+	if (mac->type == e1000_82580)
+		mac->ops.reset_hw = e1000_reset_hw_82580;
+	else
+		mac->ops.reset_hw = e1000_reset_hw_82575;
 	/* hw initialization */
 	mac->ops.init_hw = e1000_init_hw_82575;
 	/* link setup */
@@ -267,9 +300,9 @@
 	mac->ops.setup_physical_interface =
 	    (hw->phy.media_type == e1000_media_type_copper)
 	    ? e1000_setup_copper_link_82575
-	    : e1000_setup_fiber_serdes_link_82575;
+	    : e1000_setup_serdes_link_82575;
 	/* physical interface shutdown */
-	mac->ops.shutdown_serdes = e1000_shutdown_fiber_serdes_link_82575;
+	mac->ops.shutdown_serdes = e1000_shutdown_serdes_link_82575;
 	/* check for link */
 	mac->ops.check_for_link = e1000_check_for_link_82575;
 	/* receive address register setting */
@@ -300,6 +333,9 @@
 	/* link info */
 	mac->ops.get_link_up_info = e1000_get_link_up_info_82575;
 
+	/* set lan id for port to determine which phy lock to use */
+	hw->mac.ops.set_lan_id(hw);
+
 	return (E1000_SUCCESS);
 }
 
@@ -334,6 +370,10 @@
 
 	if (hw->bus.func == E1000_FUNC_1)
 		mask = E1000_SWFW_PHY1_SM;
+	else if (hw->bus.func == E1000_FUNC_2)
+		mask = E1000_SWFW_PHY2_SM;
+	else if (hw->bus.func == E1000_FUNC_3)
+		mask = E1000_SWFW_PHY3_SM;
 
 	return (e1000_acquire_swfw_sync_82575(hw, mask));
 }
@@ -353,6 +393,10 @@
 
 	if (hw->bus.func == E1000_FUNC_1)
 		mask = E1000_SWFW_PHY1_SM;
+	else if (hw->bus.func == E1000_FUNC_2)
+		mask = E1000_SWFW_PHY2_SM;
+	else if (hw->bus.func == E1000_FUNC_3)
+		mask = E1000_SWFW_PHY3_SM;
 
 	e1000_release_swfw_sync_82575(hw, mask);
 }
@@ -369,47 +413,25 @@
 static s32
 e1000_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset, u16 *data)
 {
-	struct e1000_phy_info *phy = &hw->phy;
-	u32 i, i2ccmd = 0;
+	s32 ret_val = -E1000_ERR_PARAM;
 
 	DEBUGFUNC("e1000_read_phy_reg_sgmii_82575");
 
 	if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) {
 		DEBUGOUT1("PHY Address %u is out of range\n", offset);
-		return (-E1000_ERR_PARAM);
+		goto out;
 	}
 
-	/*
-	 * Set up Op-code, Phy Address, and register address in the I2CCMD
-	 * register.  The MAC will take care of interfacing with the
-	 * PHY to retrieve the desired data.
-	 */
-	i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
-	    (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
-	    (E1000_I2CCMD_OPCODE_READ));
-
-	E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd);
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
 
-	/* Poll the ready bit to see if the I2C read completed */
-	for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
-		usec_delay(50);
-		i2ccmd = E1000_READ_REG(hw, E1000_I2CCMD);
-		if (i2ccmd & E1000_I2CCMD_READY)
-			break;
-	}
-	if (!(i2ccmd & E1000_I2CCMD_READY)) {
-		DEBUGOUT("I2CCMD Read did not complete\n");
-		return (-E1000_ERR_PHY);
-	}
-	if (i2ccmd & E1000_I2CCMD_ERROR) {
-		DEBUGOUT("I2CCMD Error bit set\n");
-		return (-E1000_ERR_PHY);
-	}
+	ret_val = e1000_read_phy_reg_i2c(hw, offset, data);
 
-	/* Need to byte-swap the 16-bit value. */
-	*data = ((i2ccmd >> 8) & 0x00FF) | ((i2ccmd << 8) & 0xFF00);
+	hw->phy.ops.release(hw);
 
-	return (E1000_SUCCESS);
+out:
+	return (ret_val);
 }
 
 /*
@@ -424,49 +446,25 @@
 static s32
 e1000_write_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset, u16 data)
 {
-	struct e1000_phy_info *phy = &hw->phy;
-	u32 i, i2ccmd = 0;
-	u16 phy_data_swapped;
+	s32 ret_val = -E1000_ERR_PARAM;
 
 	DEBUGFUNC("e1000_write_phy_reg_sgmii_82575");
 
 	if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) {
 		DEBUGOUT1("PHY Address %d is out of range\n", offset);
-		return (-E1000_ERR_PARAM);
+		goto out;
 	}
 
-	/* Swap the data bytes for the I2C interface */
-	phy_data_swapped = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00);
-
-	/*
-	 * Set up Op-code, Phy Address, and register address in the I2CCMD
-	 * register.  The MAC will take care of interfacing with the
-	 * PHY to retrieve the desired data.
-	 */
-	i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
-	    (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
-	    E1000_I2CCMD_OPCODE_WRITE |
-	    phy_data_swapped);
-
-	E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd);
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
 
-	/* Poll the ready bit to see if the I2C read completed */
-	for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
-		usec_delay(50);
-		i2ccmd = E1000_READ_REG(hw, E1000_I2CCMD);
-		if (i2ccmd & E1000_I2CCMD_READY)
-			break;
-	}
-	if (!(i2ccmd & E1000_I2CCMD_READY)) {
-		DEBUGOUT("I2CCMD Write did not complete\n");
-		return (-E1000_ERR_PHY);
-	}
-	if (i2ccmd & E1000_I2CCMD_ERROR) {
-		DEBUGOUT("I2CCMD Error bit set\n");
-		return (-E1000_ERR_PHY);
-	}
+	ret_val = e1000_write_phy_reg_i2c(hw, offset, data);
 
-	return (E1000_SUCCESS);
+	hw->phy.ops.release(hw);
+
+out:
+	return (ret_val);
 }
 
 /*
@@ -482,6 +480,7 @@
 	struct e1000_phy_info *phy = &hw->phy;
 	s32 ret_val = E1000_SUCCESS;
 	u16 phy_id;
+	u32 ctrl_ext;
 
 	DEBUGFUNC("e1000_get_phy_id_82575");
 
@@ -492,12 +491,19 @@
 	 * work.  The result of this function should mean phy->phy_addr
 	 * and phy->id are set correctly.
 	 */
-	if (!(e1000_sgmii_active_82575(hw))) {
+	if (!e1000_sgmii_active_82575(hw)) {
 		phy->addr = 1;
 		ret_val = e1000_get_phy_id(hw);
 		goto out;
 	}
 
+	/* Power on sgmii phy if it is disabled */
+	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+	E1000_WRITE_REG(hw, E1000_CTRL_EXT,
+	    ctrl_ext & ~E1000_CTRL_EXT_SDP3_DATA);
+	E1000_WRITE_FLUSH(hw);
+	msec_delay(300);
+
 	/*
 	 * The address field in the I2CCMD register is 3 bits and 0 is invalid.
 	 * Therefore, we need to test 1-7
@@ -524,10 +530,12 @@
 	if (phy->addr == 8) {
 		phy->addr = 0;
 		ret_val = -E1000_ERR_PHY;
-		goto out;
+	} else {
+		ret_val = e1000_get_phy_id(hw);
 	}
 
-	ret_val = e1000_get_phy_id(hw);
+	/* restore previous sfp cage power state */
+	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
 
 out:
 	return (ret_val);
@@ -806,6 +814,10 @@
 
 	if (hw->bus.func == E1000_FUNC_1)
 		mask = E1000_NVM_CFG_DONE_PORT_1;
+	else if (hw->bus.func == E1000_FUNC_2)
+		mask = E1000_NVM_CFG_DONE_PORT_2;
+	else if (hw->bus.func == E1000_FUNC_3)
+		mask = E1000_NVM_CFG_DONE_PORT_3;
 
 	while (timeout) {
 		if (E1000_READ_REG(hw, E1000_EEMNGCTL) & mask)
@@ -813,15 +825,14 @@
 		msec_delay(1);
 		timeout--;
 	}
-	if (!timeout) {
+	if (!timeout)
 		DEBUGOUT("MNG configuration cycle has not completed.\n");
-	}
 
 	/* If EEPROM is not marked present, init the PHY manually */
 	if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) &&
-	    (hw->phy.type == e1000_phy_igp_3)) {
+	    (hw->phy.type == e1000_phy_igp_3))
 		(void) e1000_phy_init_script_igp3(hw);
-	}
+
 	return (ret_val);
 }
 
@@ -842,14 +853,12 @@
 
 	DEBUGFUNC("e1000_get_link_up_info_82575");
 
-	if (hw->phy.media_type != e1000_media_type_copper ||
-	    e1000_sgmii_active_82575(hw)) {
+	if (hw->phy.media_type != e1000_media_type_copper)
 		ret_val = e1000_get_pcs_speed_and_duplex_82575(hw, speed,
 		    duplex);
-	} else {
+	else
 		ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed,
 		    duplex);
-	}
 
 	return (ret_val);
 }
@@ -870,8 +879,7 @@
 	DEBUGFUNC("e1000_check_for_link_82575");
 
 	/* SGMII link check is done through the PCS register. */
-	if ((hw->phy.media_type != e1000_media_type_copper) ||
-	    (e1000_sgmii_active_82575(hw))) {
+	if (hw->phy.media_type != e1000_media_type_copper) {
 		ret_val = e1000_get_pcs_speed_and_duplex_82575(hw, &speed,
 		    &duplex);
 		/*
@@ -946,23 +954,28 @@
 }
 
 /*
- * e1000_shutdown_fiber_serdes_link_82575 - Remove link during power down
+ * e1000_shutdown_serdes_link_82575 - Remove link during power down
  * @hw: pointer to the HW structure
  *
- * In the case of fiber serdes shut down optics and PCS on driver unload
+ * In the case of serdes shut down sfp and PCS on driver unload
  * when management pass thru is not enabled.
  */
 void
-e1000_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw)
+e1000_shutdown_serdes_link_82575(struct e1000_hw *hw)
 {
 	u32 reg;
 	u16 eeprom_data = 0;
 
-	if (hw->phy.media_type != e1000_media_type_internal_serdes)
+	if ((hw->phy.media_type != e1000_media_type_internal_serdes) &&
+	    !e1000_sgmii_active_82575(hw))
 		return;
 
 	if (hw->bus.func == E1000_FUNC_0)
 		hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data);
+	else if (hw->mac.type == e1000_82580)
+		hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A +
+		    NVM_82580_LAN_FUNC_OFFSET(hw->bus.func), 1,
+		    &eeprom_data);
 	else if (hw->bus.func == E1000_FUNC_1)
 		hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_B, 1, &eeprom_data);
 
@@ -979,58 +992,16 @@
 
 		/* shutdown the laser */
 		reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
-		reg |= E1000_CTRL_EXT_SDP7_DATA;
+		reg |= E1000_CTRL_EXT_SDP3_DATA;
 		E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
 
-		/* flush the write to verfiy completion */
+		/* flush the write to verify completion */
 		E1000_WRITE_FLUSH(hw);
 		msec_delay(1);
 	}
 }
 
 /*
- * e1000_vmdq_set_loopback_pf - enable or disable vmdq loopback
- * @hw: pointer to the HW structure
- * @enable: state to enter, either enabled or disabled
- *
- * enables/disables L2 switch loopback functionality
- */
-void
-e1000_vmdq_set_loopback_pf(struct e1000_hw *hw, bool enable)
-{
-	u32 reg;
-
-	reg = E1000_READ_REG(hw, E1000_DTXSWC);
-	if (enable)
-		reg |= E1000_DTXSWC_VMDQ_LOOPBACK_EN;
-	else
-		reg &= ~(E1000_DTXSWC_VMDQ_LOOPBACK_EN);
-
-	E1000_WRITE_REG(hw, E1000_DTXSWC, reg);
-}
-
-/*
- * e1000_vmdq_set_replication_pf - enable or disable vmdq replication
- * @hw: pointer to the HW structure
- * @enable: state to enter, either enabled or disabled
- *
- * enables/disables replication of packets across multiple pools
- */
-void
-e1000_vmdq_set_replication_pf(struct e1000_hw *hw, bool enable)
-{
-	u32 reg;
-
-	reg = E1000_READ_REG(hw, E1000_VT_CTL);
-	if (enable)
-		reg |= E1000_VT_CTL_VM_REPL_EN;
-	else
-		reg &= ~(E1000_VT_CTL_VM_REPL_EN);
-
-	E1000_WRITE_REG(hw, E1000_VT_CTL, reg);
-}
-
-/*
  * e1000_reset_hw_82575 - Reset hardware
  * @hw: pointer to the HW structure
  *
@@ -1130,6 +1101,11 @@
 	for (i = 0; i < mac->mta_reg_count; i++)
 		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
 
+	/* Zero out the Unicast HASH table */
+	DEBUGOUT("Zeroing the UTA\n");
+	for (i = 0; i < mac->uta_reg_count; i++)
+		E1000_WRITE_REG_ARRAY(hw, E1000_UTA, i, 0);
+
 	/* Setup link and flow control */
 	ret_val = mac->ops.setup_link(hw);
 
@@ -1157,7 +1133,6 @@
 {
 	u32 ctrl;
 	s32 ret_val;
-	bool link;
 
 	DEBUGFUNC("e1000_setup_copper_link_82575");
 
@@ -1166,6 +1141,17 @@
 	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
 
+	ret_val = e1000_setup_serdes_link_82575(hw);
+	if (ret_val)
+		goto out;
+
+	if (e1000_sgmii_active_82575(hw) && !hw->phy.reset_disable) {
+		ret_val = hw->phy.ops.reset(hw);
+		if (ret_val) {
+			DEBUGOUT("Error resetting the PHY.\n");
+			goto out;
+		}
+	}
 	switch (hw->phy.type) {
 	case e1000_phy_m88:
 		ret_val = e1000_copper_link_setup_m88(hw);
@@ -1173,6 +1159,9 @@
 	case e1000_phy_igp_3:
 		ret_val = e1000_copper_link_setup_igp(hw);
 		break;
+	case e1000_phy_82580:
+		ret_val = e1000_copper_link_setup_82577(hw);
+		break;
 	default:
 		ret_val = -E1000_ERR_PHY;
 		break;
@@ -1181,67 +1170,30 @@
 	if (ret_val)
 		goto out;
 
-	if (hw->mac.autoneg) {
-		/*
-		 * Setup autoneg and flow control advertisement
-		 * and perform autonegotiation.
-		 */
-		ret_val = e1000_copper_link_autoneg(hw);
-		if (ret_val)
-			goto out;
-	} else {
-		/*
-		 * PHY will be set to 10H, 10F, 100H or 100F
-		 * depending on user settings.
-		 */
-		DEBUGOUT("Forcing Speed and Duplex\n");
-		ret_val = hw->phy.ops.force_speed_duplex(hw);
-		if (ret_val) {
-			DEBUGOUT("Error Forcing Speed and Duplex\n");
-			goto out;
-		}
-	}
-
-	ret_val = e1000_configure_pcs_link_82575(hw);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * Check link status. Wait up to 100 microseconds for link to become
-	 * valid.
-	 */
-	ret_val = e1000_phy_has_link_generic(hw,
-	    COPPER_LINK_UP_LIMIT,
-	    10,
-	    &link);
-	if (ret_val)
-		goto out;
-
-	if (link) {
-		DEBUGOUT("Valid link established!!!\n");
-		/* Config the MAC and PHY after link is up */
-		e1000_config_collision_dist_generic(hw);
-		ret_val = e1000_config_fc_after_link_up_generic(hw);
-	} else {
-		DEBUGOUT("Unable to establish link!!!\n");
-	}
-
+	ret_val = e1000_setup_copper_link_generic(hw);
 out:
 	return (ret_val);
 }
 
 /*
- * e1000_setup_fiber_serdes_link_82575 - Setup link for fiber/serdes
+ * e1000_setup_serdes_link_82575 - Setup link for serdes
  * @hw: pointer to the HW structure
  *
- * Configures speed and duplex for fiber and serdes links.
+ * Configure the physical coding sub-layer (PCS) link.  The PCS link is
+ * used on copper connections where the serialized gigabit media independent
+ * interface (sgmii), or serdes fiber is being used.  Configures the link
+ * for auto-negotiation or forces speed/duplex.
  */
 static s32
-e1000_setup_fiber_serdes_link_82575(struct e1000_hw *hw)
+e1000_setup_serdes_link_82575(struct e1000_hw *hw)
 {
-	u32 reg;
+	u32 ctrl_reg, reg;
+
+	DEBUGFUNC("e1000_setup_serdes_link_82575");
 
-	DEBUGFUNC("e1000_setup_fiber_serdes_link_82575");
+	if ((hw->phy.media_type != e1000_media_type_internal_serdes) &&
+	    !e1000_sgmii_active_82575(hw))
+		return (E1000_SUCCESS);
 
 	/*
 	 * On the 82575, SerDes loopback mode persists until it is
@@ -1251,26 +1203,38 @@
 	 */
 	E1000_WRITE_REG(hw, E1000_SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK);
 
-	/* Force link up, set 1gb */
-	reg = E1000_READ_REG(hw, E1000_CTRL);
-	reg |= E1000_CTRL_SLU | E1000_CTRL_SPD_1000 | E1000_CTRL_FRCSPD;
+	/* power on the sfp cage if present */
+	reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
+	reg &= ~E1000_CTRL_EXT_SDP3_DATA;
+	E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
+
+	ctrl_reg = E1000_READ_REG(hw, E1000_CTRL);
+	ctrl_reg |= E1000_CTRL_SLU;
+
 	if (hw->mac.type == e1000_82575 || hw->mac.type == e1000_82576) {
 		/* set both sw defined pins */
-		reg |= E1000_CTRL_SWDPIN0 | E1000_CTRL_SWDPIN1;
-	}
-	E1000_WRITE_REG(hw, E1000_CTRL, reg);
+		ctrl_reg |= E1000_CTRL_SWDPIN0 | E1000_CTRL_SWDPIN1;
 
-	/* Power on phy for 82576 fiber adapters */
-	if (hw->mac.type == e1000_82576) {
-		reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
-		reg &= ~E1000_CTRL_EXT_SDP7_DATA;
-		E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
+		/* Set switch control to serdes energy detect */
+		reg = E1000_READ_REG(hw, E1000_CONNSW);
+		reg |= E1000_CONNSW_ENRGSRC;
+		E1000_WRITE_REG(hw, E1000_CONNSW, reg);
 	}
 
-	/* Set switch control to serdes energy detect */
-	reg = E1000_READ_REG(hw, E1000_CONNSW);
-	reg |= E1000_CONNSW_ENRGSRC;
-	E1000_WRITE_REG(hw, E1000_CONNSW, reg);
+	reg = E1000_READ_REG(hw, E1000_PCS_LCTL);
+
+	if (e1000_sgmii_active_82575(hw)) {
+		/* allow time for SFP cage to power up phy */
+		msec_delay(300);
+
+		/* AN time out should be disabled for SGMII mode */
+		reg &= ~(E1000_PCS_LCTL_AN_TIMEOUT);
+	} else {
+		ctrl_reg |= E1000_CTRL_SPD_1000 | E1000_CTRL_FRCSPD |
+		    E1000_CTRL_FD | E1000_CTRL_FRCDPX;
+	}
+
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg);
 
 	/*
 	 * New SerDes mode allows for forcing speed or autonegotiating speed
@@ -1278,35 +1242,54 @@
 	 * mode that will be compatible with older link partners and switches.
 	 * However, both are supported by the hardware and some drivers/tools.
 	 */
-	reg = E1000_READ_REG(hw, E1000_PCS_LCTL);
 
 	reg &= ~(E1000_PCS_LCTL_AN_ENABLE | E1000_PCS_LCTL_FLV_LINK_UP |
 	    E1000_PCS_LCTL_FSD | E1000_PCS_LCTL_FORCE_LINK);
 
-	if (hw->mac.autoneg) {
+	/*
+	 * We force flow control to prevent the CTRL register values from being
+	 * overwritten by the autonegotiated flow control values
+	 */
+	reg |= E1000_PCS_LCTL_FORCE_FCTRL;
+
+	/*
+	 * we always set sgmii to autoneg since it is the phy that will be
+	 * forcing the link and the serdes is just a go-between
+	 */
+	if (hw->mac.autoneg || e1000_sgmii_active_82575(hw)) {
 		/* Set PCS register for autoneg */
-		reg |= E1000_PCS_LCTL_FSV_1000 |	/* Force 1000    */
-		    E1000_PCS_LCTL_FDV_FULL |	/* SerDes Full duplex */
-		    E1000_PCS_LCTL_AN_ENABLE |	/* Enable Autoneg */
-		    E1000_PCS_LCTL_AN_RESTART;	/* Restart autoneg */
-		DEBUGOUT1("Configuring Autoneg; PCS_LCTL = 0x%08X\n", reg);
+		reg |= E1000_PCS_LCTL_FSV_1000 | /* Force 1000 */
+		    E1000_PCS_LCTL_FDV_FULL |    /* SerDes Full dplx */
+		    E1000_PCS_LCTL_AN_ENABLE |   /* Enable Autoneg */
+		    E1000_PCS_LCTL_AN_RESTART;   /* Restart autoneg */
+		DEBUGOUT1("Configuring Autoneg:PCS_LCTL=0x%08X\n", reg);
 	} else {
-		/* Set PCS register for forced speed */
-		reg |= E1000_PCS_LCTL_FLV_LINK_UP |	/* Force link up */
-		    E1000_PCS_LCTL_FSV_1000 |	/* Force 1000    */
-		    E1000_PCS_LCTL_FDV_FULL |	/* SerDes Full duplex */
-		    E1000_PCS_LCTL_FSD |	/* Force Speed */
-		    E1000_PCS_LCTL_FORCE_LINK;	/* Force Link */
-		DEBUGOUT1("Configuring Forced Link; PCS_LCTL = 0x%08X\n", reg);
-	}
+		/* Check for duplex first */
+		if (hw->mac.forced_speed_duplex & E1000_ALL_FULL_DUPLEX)
+			reg |= E1000_PCS_LCTL_FDV_FULL;
+
+		/*
+		 * No need to check for 1000/full since the spec states that
+		 * it requires autoneg to be enabled
+		 */
 
-	if (hw->mac.type == e1000_82576) {
-		reg |= E1000_PCS_LCTL_FORCE_FCTRL;
-		e1000_force_mac_fc_generic(hw);
+		/* Now set speed */
+		if (hw->mac.forced_speed_duplex & E1000_ALL_100_SPEED)
+			reg |= E1000_PCS_LCTL_FSV_100;
+
+		/* Force speed and force link */
+		reg |= E1000_PCS_LCTL_FSD |
+		    E1000_PCS_LCTL_FORCE_LINK |
+		    E1000_PCS_LCTL_FLV_LINK_UP;
+
+		DEBUGOUT1("Configuring Forced Link:PCS_LCTL=0x%08X\n", reg);
 	}
 
 	E1000_WRITE_REG(hw, E1000_PCS_LCTL, reg);
 
+	if (!e1000_sgmii_active_82575(hw))
+		(void) e1000_force_mac_fc_generic(hw);
+
 	return (E1000_SUCCESS);
 }
 
@@ -1347,73 +1330,6 @@
 }
 
 /*
- * e1000_configure_pcs_link_82575 - Configure PCS link
- * @hw: pointer to the HW structure
- *
- * Configure the physical coding sub-layer (PCS) link.  The PCS link is
- * only used on copper connections where the serialized gigabit media
- * independent interface (sgmii) is being used.  Configures the link
- * for auto-negotiation or forces speed/duplex.
- */
-static s32
-e1000_configure_pcs_link_82575(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 reg = 0;
-
-	DEBUGFUNC("e1000_configure_pcs_link_82575");
-
-	if (hw->phy.media_type != e1000_media_type_copper ||
-	    !(e1000_sgmii_active_82575(hw)))
-		goto out;
-
-	/* For SGMII, we need to issue a PCS autoneg restart */
-	reg = E1000_READ_REG(hw, E1000_PCS_LCTL);
-
-	/* AN time out should be disabled for SGMII mode */
-	reg &= ~(E1000_PCS_LCTL_AN_TIMEOUT);
-
-	if (mac->autoneg) {
-		/* Make sure forced speed and force link are not set */
-		reg &= ~(E1000_PCS_LCTL_FSD | E1000_PCS_LCTL_FORCE_LINK);
-
-		/*
-		 * The PHY should be setup prior to calling this function.
-		 * All we need to do is restart autoneg and enable autoneg.
-		 */
-		reg |= E1000_PCS_LCTL_AN_RESTART | E1000_PCS_LCTL_AN_ENABLE;
-	} else {
-		/* Set PCS register for forced speed */
-
-		/* Turn off bits for full duplex, speed, and autoneg */
-		reg &= ~(E1000_PCS_LCTL_FSV_1000 |
-		    E1000_PCS_LCTL_FSV_100 |
-		    E1000_PCS_LCTL_FDV_FULL |
-		    E1000_PCS_LCTL_AN_ENABLE);
-
-		/* Check for duplex first */
-		if (mac->forced_speed_duplex & E1000_ALL_FULL_DUPLEX)
-			reg |= E1000_PCS_LCTL_FDV_FULL;
-
-		/* Now set speed */
-		if (mac->forced_speed_duplex & E1000_ALL_100_SPEED)
-			reg |= E1000_PCS_LCTL_FSV_100;
-
-		/* Force speed and force link */
-		reg |= E1000_PCS_LCTL_FSD |
-		    E1000_PCS_LCTL_FORCE_LINK |
-		    E1000_PCS_LCTL_FLV_LINK_UP;
-
-		DEBUGOUT1("Wrote 0x%08X to PCS_LCTL to configure forced link\n",
-		    reg);
-	}
-	E1000_WRITE_REG(hw, E1000_PCS_LCTL, reg);
-
-out:
-	return (E1000_SUCCESS);
-}
-
-/*
  * e1000_sgmii_active_82575 - Return sgmii state
  * @hw: pointer to the HW structure
  *
@@ -1588,7 +1504,8 @@
 	(void) E1000_READ_REG(hw, E1000_LENERRS);
 
 	/* This register should not be read in copper configurations */
-	if (hw->phy.media_type == e1000_media_type_internal_serdes)
+	if ((hw->phy.media_type == e1000_media_type_internal_serdes) ||
+	    e1000_sgmii_active_82575(hw))
 		(void) E1000_READ_REG(hw, E1000_SCVPC);
 }
 
@@ -1720,3 +1637,226 @@
 	E1000_WRITE_REG(hw, E1000_GCR, gcr);
 	return (ret_val);
 }
+
+/*
+ * e1000_vmdq_set_loopback_pf - enable or disable vmdq loopback
+ * @hw: pointer to the hardware struct
+ * @enable: state to enter, either enabled or disabled
+ *
+ * enables/disables L2 switch loopback functionality.
+ */
+void
+e1000_vmdq_set_loopback_pf(struct e1000_hw *hw, bool enable)
+{
+	u32 dtxswc = E1000_READ_REG(hw, E1000_DTXSWC);
+
+	if (enable)
+		dtxswc |= E1000_DTXSWC_VMDQ_LOOPBACK_EN;
+	else
+		dtxswc &= ~E1000_DTXSWC_VMDQ_LOOPBACK_EN;
+
+	E1000_WRITE_REG(hw, E1000_DTXSWC, dtxswc);
+}
+
+/*
+ * e1000_vmdq_set_replication_pf - enable or disable vmdq replication
+ * @hw: pointer to the hardware struct
+ * @enable: state to enter, either enabled or disabled
+ *
+ * enables/disables replication of packets across multiple pools.
+ */
+void
+e1000_vmdq_set_replication_pf(struct e1000_hw *hw, bool enable)
+{
+	u32 vt_ctl = E1000_READ_REG(hw, E1000_VT_CTL);
+
+	if (enable)
+		vt_ctl |= E1000_VT_CTL_VM_REPL_EN;
+	else
+		vt_ctl &= ~E1000_VT_CTL_VM_REPL_EN;
+
+	E1000_WRITE_REG(hw, E1000_VT_CTL, vt_ctl);
+}
+
+/*
+ * e1000_read_phy_reg_82580 - Read 82580 MDI control register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the MDI control register in the PHY at offset and stores the
+ * information read to data.
+ */
+static s32
+e1000_read_phy_reg_82580(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	u32 mdicnfg = 0;
+	s32 ret_val;
+
+	DEBUGFUNC("e1000_read_phy_reg_82580");
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * We config the phy address in MDICNFG register now. Same bits
+	 * as before. The values in MDIC can be written but will be
+	 * ignored. This allows us to call the old function after
+	 * configuring the PHY address in the new register
+	 */
+	mdicnfg = (hw->phy.addr << E1000_MDIC_PHY_SHIFT);
+	E1000_WRITE_REG(hw, E1000_MDICNFG, mdicnfg);
+
+	ret_val = e1000_read_phy_reg_mdic(hw, offset, data);
+
+	hw->phy.ops.release(hw);
+
+out:
+	return (ret_val);
+}
+
+/*
+ * e1000_write_phy_reg_82580 - Write 82580 MDI control register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write to register at offset
+ *
+ * Writes data to MDI control register in the PHY at offset.
+ */
+static s32
+e1000_write_phy_reg_82580(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	u32 mdicnfg = 0;
+	s32 ret_val;
+
+	DEBUGFUNC("e1000_write_phy_reg_82580");
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * We config the phy address in MDICNFG register now. Same bits
+	 * as before. The values in MDIC can be written but will be
+	 * ignored. This allows us to call the old function after
+	 * configuring the PHY address in the new register
+	 */
+	mdicnfg = (hw->phy.addr << E1000_MDIC_PHY_SHIFT);
+	E1000_WRITE_REG(hw, E1000_MDICNFG, mdicnfg);
+
+	ret_val = e1000_write_phy_reg_mdic(hw, offset, data);
+
+	hw->phy.ops.release(hw);
+
+out:
+	return (ret_val);
+}
+
+/*
+ * e1000_reset_hw_82580 - Reset hardware
+ * @hw: pointer to the HW structure
+ *
+ * This resets function or entire device (all ports, etc.)
+ * to a known state.
+ */
+static s32
+e1000_reset_hw_82580(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	/* BH SW mailbox bit in SW_FW_SYNC */
+	u16 swmbsw_mask = E1000_SW_SYNCH_MB;
+	u32 ctrl;
+	bool global_device_reset = hw->dev_spec._82575.global_device_reset;
+
+	DEBUGFUNC("e1000_reset_hw_82580");
+
+	hw->dev_spec._82575.global_device_reset = false;
+
+	/* Get current control state. */
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+	/*
+	 * Prevent the PCI-E bus from sticking if there is no TLP connection
+	 * on the last TLP read/write transaction when MAC is reset.
+	 */
+	ret_val = e1000_disable_pcie_master_generic(hw);
+	if (ret_val)
+		DEBUGOUT("PCI-E Master disable polling has failed.\n");
+
+	DEBUGOUT("Masking off all interrupts\n");
+	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+	E1000_WRITE_REG(hw, E1000_RCTL, 0);
+	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
+	E1000_WRITE_FLUSH(hw);
+
+	msec_delay(10);
+
+	/* Determine whether or not a global dev reset is requested */
+	if (global_device_reset &&
+	    e1000_acquire_swfw_sync_82575(hw, swmbsw_mask))
+		global_device_reset = false;
+
+	if (global_device_reset &&
+	    !(E1000_READ_REG(hw, E1000_STATUS) & E1000_STAT_DEV_RST_SET))
+		ctrl |= E1000_CTRL_DEV_RST;
+	else
+		ctrl |= E1000_CTRL_RST;
+
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+	/* Add delay to insure DEV_RST has time to complete */
+	if (global_device_reset)
+		msec_delay(5);
+
+	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 EEPROM is not present, run manual init scripts */
+	if ((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0)
+		e1000_reset_init_script_82575(hw);
+
+	/* clear global device reset status bit */
+	E1000_WRITE_REG(hw, E1000_STATUS, E1000_STAT_DEV_RST_SET);
+
+	/* Clear any pending interrupt events. */
+	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+	(void) E1000_READ_REG(hw, E1000_ICR);
+
+	/* Install any alternate MAC address into RAR0 */
+	ret_val = e1000_check_alt_mac_addr_generic(hw);
+
+	/* Release semaphore */
+	if (global_device_reset)
+		e1000_release_swfw_sync_82575(hw, swmbsw_mask);
+
+	return (ret_val);
+}
+
+/*
+ * e1000_rxpbs_adjust_82580 - adjust RXPBS value to reflect actual RX PBA size
+ * @data: data received by reading RXPBS register
+ *
+ * The 82580 uses a table based approach for packet buffer allocation sizes.
+ * This function converts the retrieved value into the correct table value
+ *    0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7
+ * 0x0 36  72 144   1   2   4   8  16
+ * 0x8 35  70 140 rsv rsv rsv rsv rsv
+ */
+u16
+e1000_rxpbs_adjust_82580(u32 data)
+{
+	u16 ret_val = 0;
+
+	if (data < E1000_82580_RXPBS_TABLE_SIZE)
+		ret_val = e1000_82580_rxpbs_table[data];
+
+	return (ret_val);
+}
--- a/usr/src/uts/common/io/igb/igb_82575.h	Mon Nov 23 12:45:18 2009 +0800
+++ b/usr/src/uts/common/io/igb/igb_82575.h	Mon Nov 23 14:27:01 2009 +0800
@@ -26,7 +26,7 @@
  * Use is subject to license terms of the CDDL.
  */
 
-/* IntelVersion: 1.77 v2-9-8_2009-6-12 */
+/* IntelVersion: 1.85 scm_100809_154340 */
 
 #ifndef _IGB_82575_H
 #define	_IGB_82575_H
@@ -52,10 +52,14 @@
  */
 #define	E1000_RAR_ENTRIES_82575		16
 #define	E1000_RAR_ENTRIES_82576		24
+#define	E1000_RAR_ENTRIES_82580		24
+#define	E1000_SW_SYNCH_MB		0x00000100
+#define	E1000_STAT_DEV_RST_SET		0x00100000
+#define	E1000_CTRL_DEV_RST		0x20000000
 
 #ifdef E1000_BIT_FIELDS
 struct e1000_adv_data_desc {
-	u64 buffer_addr;	/* Address of the descriptor's data buffer */
+	__le64 buffer_addr;	/* Address of the descriptor's data buffer */
 	union {
 		u32 data;
 		struct {
@@ -129,6 +133,7 @@
 #define	E1000_SRRCTL_DESCTYPE_HDR_REPLICATION		0x06000000
 #define	E1000_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT	0x08000000
 #define	E1000_SRRCTL_DESCTYPE_MASK			0x0E000000
+#define	E1000_SRRCTL_TIMESTAMP				0x40000000
 #define	E1000_SRRCTL_DROP_EN				0x80000000
 
 #define	E1000_SRRCTL_BSIZEPKT_MASK	0x0000007F
@@ -143,6 +148,7 @@
 #define	E1000_MRQC_RSS_FIELD_IPV4_UDP		0x00400000
 #define	E1000_MRQC_RSS_FIELD_IPV6_UDP		0x00800000
 #define	E1000_MRQC_RSS_FIELD_IPV6_UDP_EX	0x01000000
+#define	E1000_MRQC_ENABLE_RSS_8Q		0x00000002
 
 #define	E1000_VMRCTL_MIRROR_PORT_SHIFT		8
 #define	E1000_VMRCTL_MIRROR_DSTPORT_MASK (7 << E1000_VMRCTL_MIRROR_PORT_SHIFT)
@@ -186,32 +192,32 @@
 /* Receive Descriptor - Advanced */
 union e1000_adv_rx_desc {
 	struct {
-		u64 pkt_addr;	/* Packet buffer address */
-		u64 hdr_addr;	/* Header buffer address */
+		__le64 pkt_addr;	/* Packet buffer address */
+		__le64 hdr_addr;	/* Header buffer address */
 	} read;
 	struct {
 		struct {
 			union {
-				u32 data;
+				__le32 data;
 				struct {
 					/* RSS type, Packet type */
-					u16 pkt_info;
+					__le16 pkt_info;
 					/* Split Header, header buffer length */
-					u16 hdr_info;
+					__le16 hdr_info;
 				} hs_rss;
 			} lo_dword;
 			union {
-				u32 rss;	/* RSS Hash */
+				__le32 rss;	/* RSS Hash */
 				struct {
-					u16 ip_id;	/* IP id */
-					u16 csum;	/* Packet Checksum */
+					__le16 ip_id;	/* IP id */
+					__le16 csum;	/* Packet Checksum */
 				} csum_ip;
 			} hi_dword;
 		} lower;
 		struct {
-			u32 status_error;	/* ext status/error */
-			u16 length;		/* Packet length */
-			u16 vlan;		/* VLAN tag */
+			__le32 status_error;	/* ext status/error */
+			__le16 length;		/* Packet length */
+			__le16 vlan;		/* VLAN tag */
 		} upper;
 	} wb;		/* writeback */
 };
@@ -222,6 +228,8 @@
 #define	E1000_RXDADV_HDRBUFLEN_SHIFT	5
 #define	E1000_RXDADV_SPLITHEADER_EN	0x00001000
 #define	E1000_RXDADV_SPH		0x8000
+#define	E1000_RXDADV_STAT_TS		0x10000 /* Pkt was time stamped */
+#define	E1000_RXDADV_STAT_TSIP		0x08000 /* timestamp in packet */
 #define	E1000_RXDADV_ERR_HBO		0x00800000
 
 /* RSS Hash results */
@@ -271,14 +279,14 @@
 /* Transmit Descriptor - Advanced */
 union e1000_adv_tx_desc {
 	struct {
-		u64 buffer_addr;	/* Address of descriptor's data buf */
-		u32 cmd_type_len;
-		u32 olinfo_status;
+		__le64 buffer_addr;	/* Address of descriptor's data buf */
+		__le32 cmd_type_len;
+		__le32 olinfo_status;
 	} read;
 	struct {
-		u64 rsvd;	/* Reserved */
-		u32 nxtseq_seed;
-		u32 status;
+		__le64 rsvd;	/* Reserved */
+		__le32 nxtseq_seed;
+		__le32 status;
 	} wb;
 };
 
@@ -306,10 +314,10 @@
 
 /* Context descriptors */
 struct e1000_adv_tx_context_desc {
-	u32 vlan_macip_lens;
-	u32 seqnum_seed;
-	u32 type_tucmd_mlhl;
-	u32 mss_l4len_idx;
+	__le32 vlan_macip_lens;
+	__le32 seqnum_seed;
+	__le32 type_tucmd_mlhl;
+	__le32 mss_l4len_idx;
 };
 
 #define	E1000_ADVTXD_MACLEN_SHIFT	9 /* Adv ctxt desc mac len shift */
@@ -386,6 +394,14 @@
  */
 #define	E1000_ETQF_FILTER_EAPOL		0
 
+#define	E1000_FTQF_VF_BP		0x00008000
+#define	E1000_FTQF_1588_TIME_STAMP	0x08000000
+#define	E1000_FTQF_MASK			0xF0000000
+#define	E1000_FTQF_MASK_PROTO_BP	0x10000000
+#define	E1000_FTQF_MASK_SOURCE_ADDR_BP	0x20000000
+#define	E1000_FTQF_MASK_DEST_ADDR_BP	0x40000000
+#define	E1000_FTQF_MASK_SOURCE_PORT_BP	0x80000000
+
 #define	E1000_NVM_APME_82575		0x0400
 #define	MAX_NUM_VFS			8
 
@@ -432,11 +448,21 @@
 #define	E1000_IOVCTL_REUSE_VFQ	0x00000001
 
 #define	E1000_RPLOLR_STRVLAN	0x40000000
+#define	E1000_RPLOLR_STRCRC	0x80000000
+
+#define	E1000_DTXCTL_8023LL	0x0004
+#define	E1000_DTXCTL_VLAN_ADDED	0x0008
+#define	E1000_DTXCTL_OOS_ENABLE	0x0010
+#define	E1000_DTXCTL_MDP_EN	0x0020
+#define	E1000_DTXCTL_SPOOF_INT	0x0040
 
 #define	ALL_QUEUES		0xFFFF
 
+/* RX packet buffer size defines */
+#define	E1000_RXPBS_SIZE_MASK_82576	0x0000007F
 void e1000_vmdq_set_loopback_pf(struct e1000_hw *hw, bool enable);
 void e1000_vmdq_set_replication_pf(struct e1000_hw *hw, bool enable);
+u16 e1000_rxpbs_adjust_82580(u32 data);
 
 #ifdef __cplusplus
 }
--- a/usr/src/uts/common/io/igb/igb_api.c	Mon Nov 23 12:45:18 2009 +0800
+++ b/usr/src/uts/common/io/igb/igb_api.c	Mon Nov 23 14:27:01 2009 +0800
@@ -26,7 +26,7 @@
  * Use is subject to license terms of the CDDL.
  */
 
-/* IntelVersion: 1.122 v2-9-8_2009-6-12 */
+/* IntelVersion: 1.128 scm_100809_154340 */
 
 #include "igb_api.h"
 
@@ -139,9 +139,17 @@
 	case E1000_DEV_ID_82576_SERDES:
 	case E1000_DEV_ID_82576_QUAD_COPPER:
 	case E1000_DEV_ID_82576_NS:
+	case E1000_DEV_ID_82576_NS_SERDES:
 	case E1000_DEV_ID_82576_SERDES_QUAD:
 		mac->type = e1000_82576;
 		break;
+	case E1000_DEV_ID_82580_COPPER:
+	case E1000_DEV_ID_82580_FIBER:
+	case E1000_DEV_ID_82580_SERDES:
+	case E1000_DEV_ID_82580_SGMII:
+	case E1000_DEV_ID_82580_COPPER_DUAL:
+		mac->type = e1000_82580;
+		break;
 	default:
 		/* Should never have loaded on this device */
 		ret_val = -E1000_ERR_MAC_INIT;
@@ -197,6 +205,7 @@
 	switch (hw->mac.type) {
 	case e1000_82575:
 	case e1000_82576:
+	case e1000_82580:
 		e1000_init_function_pointers_82575(hw);
 		break;
 	default:
--- a/usr/src/uts/common/io/igb/igb_api.h	Mon Nov 23 12:45:18 2009 +0800
+++ b/usr/src/uts/common/io/igb/igb_api.h	Mon Nov 23 14:27:01 2009 +0800
@@ -26,7 +26,7 @@
  * Use is subject to license terms of the CDDL.
  */
 
-/* IntelVersion: 1.52 v2-9-8_2009-6-12 */
+/* IntelVersion: 1.53 scm_100809_154340 */
 
 #ifndef _IGB_API_H
 #define	_IGB_API_H
--- a/usr/src/uts/common/io/igb/igb_defines.h	Mon Nov 23 12:45:18 2009 +0800
+++ b/usr/src/uts/common/io/igb/igb_defines.h	Mon Nov 23 14:27:01 2009 +0800
@@ -26,7 +26,7 @@
  * Use is subject to license terms of the CDDL.
  */
 
-/* IntelVersion: 1.111 v2-9-8_2009-6-12 */
+/* IntelVersion: 1.119 scm_100809_154340 */
 
 #ifndef _IGB_DEFINES_H
 #define	_IGB_DEFINES_H
@@ -118,12 +118,12 @@
 #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 */
@@ -134,6 +134,8 @@
 /* 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_82580_MASK	0x01C00000 /* 82580 bit 24:22 */
+#define	E1000_CTRL_EXT_LINK_MODE_1000BASE_KX	0x00400000
 #define	E1000_CTRL_EXT_LINK_MODE_GMII	0x00000000
 #define	E1000_CTRL_EXT_LINK_MODE_TBI	0x00C00000
 #define	E1000_CTRL_EXT_LINK_MODE_KMRN	0x00000000
@@ -353,6 +355,8 @@
 #define	E1000_SWFW_PHY0_SM	0x2
 #define	E1000_SWFW_PHY1_SM	0x4
 #define	E1000_SWFW_CSR_SM	0x8
+#define	E1000_SWFW_PHY2_SM	0x20
+#define	E1000_SWFW_PHY3_SM	0x40
 
 /* FACTPS Definitions */
 #define	E1000_FACTPS_LFS	0x40000000  /* LAN Function Select */
@@ -654,6 +658,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
@@ -727,6 +732,7 @@
 #define	E1000_ICR_ACK		0x00020000 /* Receive Ack frame */
 #define	E1000_ICR_MNG		0x00040000 /* Manageability event */
 #define	E1000_ICR_DOCK		0x00080000 /* Dock/Undock */
+#define	E1000_ICR_DRSTA		0x40000000 /* Device Reset Asserted */
 /* If this bit asserted, the driver should claim the interrupt */
 #define	E1000_ICR_INT_ASSERTED	0x80000000
 #define	E1000_ICR_RXD_FIFO_PAR0	0x00100000 /* Q0 Rx desc FIFO parity error */
@@ -742,6 +748,7 @@
 #define	E1000_ICR_PHYINT	0x00001000
 #define	E1000_ICR_DOUTSYNC	0x10000000 /* NIC DMA out of sync */
 #define	E1000_ICR_EPRST		0x00100000 /* ME hardware reset occurs */
+#define	E1000_ICR_FER		0x00400000 /* Fatal Error */
 
 /* Extended Interrupt Cause Read */
 #define	E1000_EICR_RX_QUEUE0	0x00000001 /* Rx Queue 0 Interrupt */
@@ -806,6 +813,7 @@
 #define	E1000_IMS_ACK		E1000_ICR_ACK	/* Receive Ack frame */
 #define	E1000_IMS_MNG		E1000_ICR_MNG	/* Manageability event */
 #define	E1000_IMS_DOCK		E1000_ICR_DOCK	/* Dock/Undock */
+#define	E1000_IMS_DRSTA		E1000_ICR_DRSTA	/* Device Reset Asserted */
 /* queue 0 Rx descriptor FIFO parity error */
 #define	E1000_IMS_RXD_FIFO_PAR0	E1000_ICR_RXD_FIFO_PAR0
 /* queue 0 Tx descriptor FIFO parity error */
@@ -822,6 +830,7 @@
 #define	E1000_IMS_PHYINT	E1000_ICR_PHYINT
 #define	E1000_IMS_DOUTSYNC	E1000_ICR_DOUTSYNC /* NIC DMA out of sync */
 #define	E1000_IMS_EPRST		E1000_ICR_EPRST
+#define	E1000_IMS_FER		E1000_ICR_FER /* Fatal Error */
 
 /* Extended Interrupt Mask Set */
 #define	E1000_EIMS_RX_QUEUE0	E1000_EICR_RX_QUEUE0 /* Rx Queue 0 Interrupt */
@@ -854,6 +863,7 @@
 #define	E1000_ICS_ACK		E1000_ICR_ACK	/* Receive Ack frame */
 #define	E1000_ICS_MNG		E1000_ICR_MNG	/* Manageability event */
 #define	E1000_ICS_DOCK		E1000_ICR_DOCK	/* Dock/Undock */
+#define	E1000_ICS_DRSTA		E1000_ICR_DRSTA	/* Device Reset Aserted */
 /* queue 0 Rx descriptor FIFO parity error */
 #define	E1000_ICS_RXD_FIFO_PAR0	E1000_ICR_RXD_FIFO_PAR0
 /* queue 0 Tx descriptor FIFO parity error */
@@ -977,6 +987,25 @@
 #define	E1000_RXCW_SYNCH	0x40000000 /* Receive config synch */
 #define	E1000_RXCW_ANC		0x80000000 /* Auto-neg complete */
 
+/* TUPLE Filtering Configuration */
+#define	E1000_TTQF_DISABLE_MASK		0xF0008000 /* TTQF Disable Mask */
+#define	E1000_TTQF_QUEUE_ENABLE		0x100 /* TTQF Queue Enable Bit */
+#define	E1000_TTQF_PROTOCOL_MASK	0xFF /* TTQF Protocol Mask */
+/* TTQF TCP Bit, shift with E1000_TTQF_PROTOCOL SHIFT */
+#define	E1000_TTQF_PROTOCOL_TCP		0x0
+/* TTQF UDP Bit, shift with E1000_TTQF_PROTOCOL_SHIFT */
+#define	E1000_TTQF_PROTOCOL_UDP		0x1
+/* TTQF SCTP Bit, shift with E1000_TTQF_PROTOCOL_SHIFT */
+#define	E1000_TTQF_PROTOCOL_SCTP	0x2
+#define	E1000_TTQF_PROTOCOL_SHIFT	5 /* TTQF Protocol Shift */
+#define	E1000_TTQF_QUEUE_SHIFT		16 /* TTQF Queue Shfit */
+#define	E1000_TTQF_RX_QUEUE_MASK	0x70000 /* TTQF Queue Mask */
+#define	E1000_TTQF_MASK_ENABLE		0x10000000 /* TTQF Mask Enable Bit */
+#define	E1000_IMIR_CLEAR_MASK		0xF001FFFF /* IMIR Reg Clear Mask */
+#define	E1000_IMIR_PORT_BYPASS		0x20000 /* IMIR Port Bypass Bit */
+#define	E1000_IMIR_PRIORITY_SHIFT	29 /* IMIR Priority Shift */
+#define	E1000_IMIREXT_CLEAR_MASK	0x7FFFF /* IMIREXT Reg Clear Mask */
+
 /* PCI Express Control */
 #define	E1000_GCR_RXD_NO_SNOOP		0x00000001
 #define	E1000_GCR_RXDSCW_NO_SNOOP	0x00000002
@@ -1167,6 +1196,10 @@
 
 #define	E1000_NVM_CFG_DONE_PORT_0	0x40000 /* MNG config cycle done */
 #define	E1000_NVM_CFG_DONE_PORT_1	0x80000 /* ...for second port */
+#define	E1000_NVM_CFG_DONE_PORT_2	0x100000 /* ...for third port */
+#define	E1000_NVM_CFG_DONE_PORT_3	0x200000 /* ...for fourth port */
+
+#define	NVM_82580_LAN_FUNC_OFFSET(a) (a ? (0x40 + (0x40 * a)) : 0)
 
 /* Mask bits for fields in Word	0x0f of the NVM */
 #define	NVM_WORD0F_PAUSE_MASK		0x3000
@@ -1272,6 +1305,7 @@
 #define	IFE_E_PHY_ID		0x02A80330
 #define	IFE_PLUS_E_PHY_ID	0x02A80320
 #define	IFE_C_E_PHY_ID		0x02A80310
+#define	I82580_I_PHY_ID		0x015403A0
 #define	IGP04E1000_E_PHY_ID	0x02A80391
 #define	M88_VENDOR		0x0141
 
@@ -1494,6 +1528,34 @@
 #define	E1000_LSECRXCTRL_RP		0x00000080
 #define	E1000_LSECRXCTRL_RSV_MASK	0xFFFFFF33
 
+/* DMA Coalescing register fields */
+
+/* DMA Coalescing Watchdog Timer */
+#define	E1000_DMACR_DMACWT_MASK		0x00003FFF
+/* DMA Coalescing Receive Threshold */
+#define	E1000_DMACR_DMACTHR_MASK	0x00FF0000
+#define	E1000_DMACR_DMACTHR_SHIFT	16
+/* Lx when no PCIe transactions */
+#define	E1000_DMACR_DMAC_LX_MASK	0x30000000
+#define	E1000_DMACR_DMAC_LX_SHIFT	28
+/* Enable DMA Coalescing */
+#define	E1000_DMACR_DMAC_EN		0x80000000
+/* DMA Coalescing Transmit Threshold */
+#define	E1000_DMCTXTH_DMCTTHR_MASK	0x00000FFF
+/* Time to LX request */
+#define	E1000_DMCTLX_TTLX_MASK		0x00000FFF
+/* Receive Traffic Rate Threshold */
+#define	E1000_DMCRTRH_UTRESH_MASK	0x0007FFFF
+/* Rcv packet rate in current window */
+#define	E1000_DMCRTRH_LRPRCW		0x80000000
+/* DMA Coal Rcv Traffic Current Cnt */
+#define	E1000_DMCCNT_CCOUNT_MASK	0x01FFFFFF
+/* Flow ctrl Rcv Threshold High val */
+#define	E1000_FCRTC_RTH_COAL_MASK	0x0003FFF0
+#define	E1000_FCRTC_RTH_COAL_SHIFT	4
+/* Lx power decision based on DMA coal */
+#define	E1000_PCIEMISC_LX_DECISION	0x00000080
+
 #ifdef __cplusplus
 }
 #endif
--- a/usr/src/uts/common/io/igb/igb_hw.h	Mon Nov 23 12:45:18 2009 +0800
+++ b/usr/src/uts/common/io/igb/igb_hw.h	Mon Nov 23 14:27:01 2009 +0800
@@ -26,7 +26,7 @@
  * Use is subject to license terms of the CDDL.
  */
 
-/* IntelVersion: 1.398 v2008-10-7 */
+/* IntelVersion: 1.444 scm_100809_154340 */
 
 #ifndef _IGB_HW_H
 #define	_IGB_HW_H
@@ -46,10 +46,16 @@
 #define	E1000_DEV_ID_82576_SERDES		0x10E7
 #define	E1000_DEV_ID_82576_QUAD_COPPER		0x10E8
 #define	E1000_DEV_ID_82576_NS			0x150A
+#define	E1000_DEV_ID_82576_NS_SERDES		0x1518
 #define	E1000_DEV_ID_82576_SERDES_QUAD		0x150D
 #define	E1000_DEV_ID_82575EB_COPPER		0x10A7
 #define	E1000_DEV_ID_82575EB_FIBER_SERDES	0x10A9
 #define	E1000_DEV_ID_82575GB_QUAD_COPPER	0x10D6
+#define	E1000_DEV_ID_82580_COPPER		0x150E
+#define	E1000_DEV_ID_82580_FIBER		0x150F
+#define	E1000_DEV_ID_82580_SERDES		0x1510
+#define	E1000_DEV_ID_82580_SGMII		0x1511
+#define	E1000_DEV_ID_82580_COPPER_DUAL		0x1516
 
 #define	E1000_REVISION_0 0
 #define	E1000_REVISION_1 1
@@ -59,13 +65,19 @@
 
 #define	E1000_FUNC_0	0
 #define	E1000_FUNC_1	1
+#define	E1000_FUNC_2	2
+#define	E1000_FUNC_3	3
+
 #define	E1000_ALT_MAC_ADDRESS_OFFSET_LAN0	0
 #define	E1000_ALT_MAC_ADDRESS_OFFSET_LAN1	3
+#define	E1000_ALT_MAC_ADDRESS_OFFSET_LAN2	6
+#define	E1000_ALT_MAC_ADDRESS_OFFSET_LAN3	9
 
 enum e1000_mac_type {
 	e1000_undefined = 0,
 	e1000_82575,
 	e1000_82576,
+	e1000_82580,
 	e1000_num_macs  /* List is 1-based, so subtract 1 for true count. */
 };
 
@@ -103,6 +115,7 @@
 	e1000_phy_gg82563,
 	e1000_phy_igp_3,
 	e1000_phy_ife,
+	e1000_phy_82580,
 	e1000_phy_vf
 };
 
@@ -490,11 +503,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 *);
 };
@@ -532,6 +547,7 @@
 	u16 ifs_ratio;
 	u16 ifs_step_size;
 	u16 mta_reg_count;
+	u16 uta_reg_count;
 
 	/* Maximum size of the MTA register table in all supported adapters */
 #define	MAX_MTA_REG 128
--- a/usr/src/uts/common/io/igb/igb_mac.c	Mon Nov 23 12:45:18 2009 +0800
+++ b/usr/src/uts/common/io/igb/igb_mac.c	Mon Nov 23 14:27:01 2009 +0800
@@ -26,7 +26,7 @@
  * Use is subject to license terms of the CDDL.
  */
 
-/* IntelVersion: 1.104 v2-9-8_2009-6-12 */
+/* IntelVersion: 1.108 scm_100809_154340 */
 
 #include "igb_api.h"
 
@@ -346,6 +346,10 @@
 
 	if (hw->bus.func == E1000_FUNC_1)
 		nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1;
+	if (hw->bus.func == E1000_FUNC_2)
+		nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN2;
+	if (hw->bus.func == E1000_FUNC_3)
+		nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN3;
 	for (i = 0; i < ETH_ADDR_LEN; i += 2) {
 		offset = nvm_alt_mac_addr_offset + (i >> 1);
 		ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
@@ -2074,7 +2078,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/igb/igb_mac.h	Mon Nov 23 12:45:18 2009 +0800
+++ b/usr/src/uts/common/io/igb/igb_mac.h	Mon Nov 23 14:27:01 2009 +0800
@@ -26,7 +26,7 @@
  * Use is subject to license terms of the CDDL.
  */
 
-/* IntelVersion: 1.32 v2-9-8_2009-6-12 */
+/* IntelVersion: 1.32 scm_100809_154340 */
 
 #ifndef	_IGB_MAC_H
 #define	_IGB_MAC_H
--- a/usr/src/uts/common/io/igb/igb_main.c	Mon Nov 23 12:45:18 2009 +0800
+++ b/usr/src/uts/common/io/igb/igb_main.c	Mon Nov 23 14:27:01 2009 +0800
@@ -29,7 +29,7 @@
 #include "igb_sw.h"
 
 static char ident[] = "Intel 1Gb Ethernet";
-static char igb_version[] = "igb 1.1.8";
+static char igb_version[] = "igb 1.1.9";
 
 /*
  * Local function protoypes
@@ -74,6 +74,7 @@
 static void igb_disable_adapter_interrupts(igb_t *);
 static void igb_enable_adapter_interrupts_82575(igb_t *);
 static void igb_enable_adapter_interrupts_82576(igb_t *);
+static void igb_enable_adapter_interrupts_82580(igb_t *);
 static boolean_t is_valid_mac_addr(uint8_t *);
 static boolean_t igb_stall_check(igb_t *);
 static boolean_t igb_set_loopback_mode(igb_t *, uint32_t);
@@ -91,6 +92,7 @@
 static int igb_disable_intrs(igb_t *);
 static void igb_setup_msix_82575(igb_t *);
 static void igb_setup_msix_82576(igb_t *);
+static void igb_setup_msix_82580(igb_t *);
 static uint_t igb_intr_legacy(void *, void *);
 static uint_t igb_intr_msi(void *, void *);
 static uint_t igb_intr_rx(void *, void *);
@@ -233,6 +235,30 @@
 	0xffe00000		/* mask for RXDCTL register */
 };
 
+static adapter_info_t igb_82580_cap = {
+	/* limits */
+	8,		/* maximum number of rx queues */
+	1,		/* minimum number of rx queues */
+	4,		/* default number of rx queues */
+	8,		/* maximum number of tx queues */
+	1,		/* minimum number of tx queues */
+	4,		/* default number of tx queues */
+	65535,		/* maximum interrupt throttle rate */
+	0,		/* minimum interrupt throttle rate */
+	200,		/* default interrupt throttle rate */
+
+	/* function pointers */
+	igb_enable_adapter_interrupts_82580,
+	igb_setup_msix_82580,
+
+	/* capabilities */
+	(IGB_FLAG_HAS_DCA |	/* capability flags */
+	IGB_FLAG_VMDQ_POOL |
+	IGB_FLAG_NEED_CTX_IDX),
+
+	0xffe00000		/* mask for RXDCTL register */
+};
+
 /*
  * Module Initialization Functions
  */
@@ -812,6 +838,9 @@
 	case e1000_82576:
 		igb->capab = &igb_82576_cap;
 		break;
+	case e1000_82580:
+		igb->capab = &igb_82580_cap;
+		break;
 	default:
 		return (IGB_FAILURE);
 	}
@@ -1257,7 +1286,7 @@
 	hw->fc.pause_time = E1000_FC_PAUSE_TIME;
 	hw->fc.send_xon = B_TRUE;
 
-	e1000_validate_mdi_setting(hw);
+	(void) e1000_validate_mdi_setting(hw);
 
 	/*
 	 * Reset the chipset hardware the second time to put PBA settings
@@ -1915,31 +1944,15 @@
 	 * wakeup but leave this here for completeness.
 	 */
 	rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
-
-	switch (hw->mac.type) {
-	case e1000_82575:
-		rctl |= (E1000_RCTL_EN |	/* Enable Receive Unit */
-		    E1000_RCTL_BAM |		/* Accept Broadcast Packets */
-		    E1000_RCTL_LPE |		/* Large Packet Enable */
-						/* Multicast filter offset */
-		    (hw->mac.mc_filter_type << E1000_RCTL_MO_SHIFT) |
-		    E1000_RCTL_RDMTS_HALF |	/* rx descriptor threshold */
-		    E1000_RCTL_SECRC);		/* Strip Ethernet CRC */
-		break;
-
-	case e1000_82576:
-		rctl |= (E1000_RCTL_EN |	/* Enable Receive Unit */
-		    E1000_RCTL_BAM |		/* Accept Broadcast Packets */
-		    E1000_RCTL_LPE |		/* Large Packet Enable */
-						/* Multicast filter offset */
-		    (hw->mac.mc_filter_type << E1000_RCTL_MO_SHIFT) |
-		    E1000_RCTL_SECRC);		/* Strip Ethernet CRC */
-		break;
-
-	default:
-		igb_log(igb, "unsupported MAC type: %d", hw->mac.type);
-		return;	/* should never come here; this will cause rx failure */
-	}
+	rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);
+
+	rctl |= (E1000_RCTL_EN |	/* Enable Receive Unit */
+	    E1000_RCTL_BAM |		/* Accept Broadcast Packets */
+	    E1000_RCTL_LPE |		/* Large Packet Enable */
+					/* Multicast filter offset */
+	    (hw->mac.mc_filter_type << E1000_RCTL_MO_SHIFT) |
+	    E1000_RCTL_RDMTS_HALF |	/* rx descriptor threshold */
+	    E1000_RCTL_SECRC);		/* Strip Ethernet CRC */
 
 	for (i = 0; i < igb->num_rx_groups; i++) {
 		rx_group = &igb->rx_groups[i];
@@ -2175,7 +2188,7 @@
 
 	/* Setup the Redirection Table */
 	if (hw->mac.type == e1000_82576) {
-		shift = 0;
+		shift = 3;
 	} else if (hw->mac.type == e1000_82575) {
 		shift = 6;
 	}
@@ -2683,10 +2696,10 @@
 	igb->num_rx_groups = igb_get_prop(igb, PROP_RX_GROUP_NUM,
 	    MIN_RX_GROUP_NUM, MAX_RX_GROUP_NUM, DEFAULT_RX_GROUP_NUM);
 	/*
-	 * Currently we do not support VMDq for 82576.
+	 * Currently we do not support VMDq for 82576 and 82580.
 	 * If it is e1000_82576, set num_rx_groups to 1.
 	 */
-	if (hw->mac.type == e1000_82576)
+	if (hw->mac.type >= e1000_82576)
 		igb->num_rx_groups = 1;
 
 	if (igb->mr_enable) {
@@ -2998,8 +3011,8 @@
 /*
  * igb_local_timer - driver watchdog function
  *
- * This function will handle the transmit stall check, link status check and
- * other routines.
+ * This function will handle the hardware stall check, link status
+ * check and other routines.
  */
 static void
 igb_local_timer(void *arg)
@@ -3007,10 +3020,14 @@
 	igb_t *igb = (igb_t *)arg;
 	boolean_t link_changed = B_FALSE;
 
-	if (igb_stall_check(igb)) {
+	if (igb_stall_check(igb))
+		igb->igb_state |= IGB_STALL;
+
+	if (igb->igb_state & IGB_STALL) {
 		igb_fm_ereport(igb, DDI_FM_DEVICE_STALL);
 		ddi_fm_service_impact(igb->dip, DDI_SERVICE_LOST);
 		igb->reset_count++;
+		igb->igb_state &= ~IGB_STALL;
 		if (igb_reset(igb) == IGB_SUCCESS)
 			ddi_fm_service_impact(igb->dip,
 			    DDI_SERVICE_RESTORED);
@@ -3045,6 +3062,7 @@
 igb_stall_check(igb_t *igb)
 {
 	igb_tx_ring_t *tx_ring;
+	struct e1000_hw *hw = &igb->hw;
 	boolean_t result;
 	int i;
 
@@ -3065,6 +3083,10 @@
 
 		if (tx_ring->stall_watchdog >= STALL_WATCHDOG_TIMEOUT) {
 			result = B_TRUE;
+			if (hw->mac.type == e1000_82580) {
+				hw->dev_spec._82575.global_device_reset
+				    = B_TRUE;
+			}
 			break;
 		}
 	}
@@ -3307,6 +3329,38 @@
 }
 
 /*
+ * igb_enable_adapter_interrupts_82580 - Enable NIC interrupts for 82580
+ */
+static void
+igb_enable_adapter_interrupts_82580(igb_t *igb)
+{
+	struct e1000_hw *hw = &igb->hw;
+
+	/* Clear any pending interrupts */
+	(void) E1000_READ_REG(hw, E1000_ICR);
+	igb->ims_mask |= E1000_IMS_DRSTA;
+
+	if (igb->intr_type == DDI_INTR_TYPE_MSIX) {
+
+		/* Interrupt enabling for MSI-X */
+		E1000_WRITE_REG(hw, E1000_EIMS, igb->eims_mask);
+		E1000_WRITE_REG(hw, E1000_EIAC, igb->eims_mask);
+		igb->ims_mask = (E1000_IMS_LSC | E1000_IMS_DRSTA);
+		E1000_WRITE_REG(hw, E1000_IMS, igb->ims_mask);
+	} else { /* Interrupt enabling for MSI and legacy */
+		E1000_WRITE_REG(hw, E1000_IVAR0, E1000_IVAR_VALID);
+		igb->ims_mask = IMS_ENABLE_MASK | E1000_IMS_TXQE;
+		igb->ims_mask |= E1000_IMS_DRSTA;
+		E1000_WRITE_REG(hw, E1000_IMS, igb->ims_mask);
+	}
+
+	/* Disable auto-mask for ICR interrupt bits */
+	E1000_WRITE_REG(hw, E1000_IAM, 0);
+
+	E1000_WRITE_FLUSH(hw);
+}
+
+/*
  * igb_enable_adapter_interrupts_82576 - Enable NIC interrupts for 82576
  */
 static void
@@ -3816,6 +3870,11 @@
 			igb_get_phy_state(igb);
 		}
 
+		if (icr & E1000_ICR_DRSTA) {
+			/* 82580 Full Device Reset needed */
+			igb->igb_state |= IGB_STALL;
+		}
+
 		result = DDI_INTR_CLAIMED;
 	} else {
 		/*
@@ -3880,6 +3939,11 @@
 		igb_intr_link_work(igb);
 	}
 
+	if (icr & E1000_ICR_DRSTA) {
+		/* 82580 Full Device Reset needed */
+		igb->igb_state |= IGB_STALL;
+	}
+
 	return (DDI_INTR_CLAIMED);
 }
 
@@ -3961,6 +4025,11 @@
 		IGB_STAT(igb->dout_sync);
 	}
 
+	if (icr & E1000_ICR_DRSTA) {
+		/* 82580 Full Device Reset needed */
+		igb->igb_state |= IGB_STALL;
+	}
+
 	return (DDI_INTR_CLAIMED);
 }
 
@@ -4481,6 +4550,96 @@
 }
 
 /*
+ * igb_setup_msix_82580 - setup 82580 adapter to use MSI-X interrupts
+ *
+ * 82580 uses same table approach at 82576 but has fewer entries.  Each
+ * queue has a single entry in the table to which we write a vector number
+ * along with a "valid" bit.  Vectors take a different position in the
+ * register depending on * whether * they are numbered above or below 4.
+ */
+static void
+igb_setup_msix_82580(igb_t *igb)
+{
+	struct e1000_hw *hw = &igb->hw;
+	uint32_t ivar, index, vector;
+	int i;
+
+	/* must enable msi-x capability before IVAR settings */
+	E1000_WRITE_REG(hw, E1000_GPIE, (E1000_GPIE_MSIX_MODE |
+	    E1000_GPIE_PBA | E1000_GPIE_NSICR | E1000_GPIE_EIAME));
+	/*
+	 * Set vector for tx ring 0 and other causes.
+	 * NOTE assumption that it is vector 0.
+	 * This is also interdependent with installation of interrupt service
+	 * routines in igb_add_intr_handlers().
+	 */
+
+	/* assign "other" causes to vector 0 */
+	vector = 0;
+	ivar = ((vector | E1000_IVAR_VALID) << 8);
+	E1000_WRITE_REG(hw, E1000_IVAR_MISC, ivar);
+
+	/* assign tx ring 0 to vector 0 */
+	ivar = ((vector | E1000_IVAR_VALID) << 8);
+	E1000_WRITE_REG(hw, E1000_IVAR0, ivar);
+
+	/* prepare to enable tx & other interrupt causes */
+	igb->eims_mask = (1 << vector);
+
+	vector ++;
+
+	for (i = 0; i < igb->num_rx_rings; i++) {
+		/*
+		 * Set vector for each rx ring
+		 */
+		index = (i >> 1);
+		ivar = E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index);
+
+		if (i & 1) {
+			/* vector goes into third byte of register */
+			ivar = ivar & 0xFF00FFFF;
+			ivar |= ((vector | E1000_IVAR_VALID) << 16);
+		} else {
+			/* vector goes into low byte of register */
+			ivar = ivar & 0xFFFFFF00;
+			ivar |= (vector | E1000_IVAR_VALID);
+		}
+		E1000_WRITE_REG_ARRAY(hw, E1000_IVAR0, index, ivar);
+
+		/* Accumulate interrupt-cause bits to enable */
+		igb->eims_mask |= (1 << vector);
+
+		vector ++;
+	}
+
+	for (i = 1; i < igb->num_tx_rings; i++) {
+		/*
+		 * Set vector for each tx ring from 2nd tx ring.
+		 * Note assumption that tx vectors numericall follow rx vectors.
+		 */
+		index = (i >> 1);
+		ivar = E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index);
+
+		if (i & 1) {
+			/* vector goes into high byte of register */
+			ivar = ivar & 0x00FFFFFF;
+			ivar |= ((vector | E1000_IVAR_VALID) << 24);
+		} else {
+			/* vector goes into second byte of register */
+			ivar = ivar & 0xFFFF00FF;
+			ivar |= (vector | E1000_IVAR_VALID) << 8;
+		}
+		E1000_WRITE_REG_ARRAY(hw, E1000_IVAR0, index, ivar);
+
+		/* Accumulate interrupt-cause bits to enable */
+		igb->eims_mask |= (1 << vector);
+
+		vector ++;
+	}
+	ASSERT(vector == igb->intr_cnt);
+}
+
+/*
  * igb_rem_intr_handlers - remove the interrupt handlers
  */
 static void
--- a/usr/src/uts/common/io/igb/igb_manage.c	Mon Nov 23 12:45:18 2009 +0800
+++ b/usr/src/uts/common/io/igb/igb_manage.c	Mon Nov 23 14:27:01 2009 +0800
@@ -26,7 +26,7 @@
  * Use is subject to license terms of the CDDL.
  */
 
-/* IntelVersion: 1.27 v2-9-8_2009-6-12 */
+/* IntelVersion: 1.27 scm_100809_154340 */
 
 #include "igb_api.h"
 
--- a/usr/src/uts/common/io/igb/igb_manage.h	Mon Nov 23 12:45:18 2009 +0800
+++ b/usr/src/uts/common/io/igb/igb_manage.h	Mon Nov 23 14:27:01 2009 +0800
@@ -26,7 +26,7 @@
  * Use is subject to license terms of the CDDL.
  */
 
-/* IntelVersion: 1.18 v2-9-8_2009-6-12 */
+/* IntelVersion: 1.18 scm_100809_154340 */
 
 #ifndef _IGB_MANAGE_H
 #define	_IGB_MANAGE_H
--- a/usr/src/uts/common/io/igb/igb_nvm.c	Mon Nov 23 12:45:18 2009 +0800
+++ b/usr/src/uts/common/io/igb/igb_nvm.c	Mon Nov 23 14:27:01 2009 +0800
@@ -26,7 +26,7 @@
  * Use is subject to license terms of the CDDL.
  */
 
-/* IntelVersion: 1.49 v2-9-8_2009-6-12 */
+/* IntelVersion: 1.49 scm_100809_154340 */
 
 #include "igb_api.h"
 
--- a/usr/src/uts/common/io/igb/igb_nvm.h	Mon Nov 23 12:45:18 2009 +0800
+++ b/usr/src/uts/common/io/igb/igb_nvm.h	Mon Nov 23 14:27:01 2009 +0800
@@ -26,7 +26,7 @@
  * Use is subject to license terms of the CDDL.
  */
 
-/* IntelVersion: 1.18 v2-9-8_2009-6-12 */
+/* IntelVersion: 1.18 scm_100809_154340 */
 
 #ifndef _IGB_NVM_H
 #define	_IGB_NVM_H
--- a/usr/src/uts/common/io/igb/igb_osdep.h	Mon Nov 23 12:45:18 2009 +0800
+++ b/usr/src/uts/common/io/igb/igb_osdep.h	Mon Nov 23 14:27:01 2009 +0800
@@ -69,7 +69,7 @@
 #define	DEBUGOUT3(S, A, B, C)
 #endif
 
-#define	DEBUGFUNC(F)
+#define	DEBUGFUNC(f)
 
 #define	OS_DEP(hw)		((struct igb_osdep *)((hw)->back))
 
--- a/usr/src/uts/common/io/igb/igb_phy.c	Mon Nov 23 12:45:18 2009 +0800
+++ b/usr/src/uts/common/io/igb/igb_phy.c	Mon Nov 23 14:27:01 2009 +0800
@@ -26,10 +26,11 @@
  * Use is subject to license terms of the CDDL.
  */
 
-/* IntelVersion: 1.140 v2-9-8_2009-6-12 */
+/* IntelVersion: 1.155 scm_100809_154340 */
 
 #include "igb_api.h"
 
+static s32 e1000_copper_link_autoneg(struct e1000_hw *hw);
 static s32 e1000_phy_setup_autoneg(struct e1000_hw *hw);
 
 /* Cable length tables */
@@ -77,11 +78,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;
 }
@@ -328,6 +331,107 @@
 }
 
 /*
+ * e1000_read_phy_reg_i2c - Read PHY register using i2c
+ * @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 i2c interface and stores the
+ * retrieved information in data.
+ */
+s32
+e1000_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 i, i2ccmd = 0;
+
+	DEBUGFUNC("e1000_read_phy_reg_i2c");
+
+	/*
+	 * Set up Op-code, Phy Address, and register address in the I2CCMD
+	 * register.  The MAC will take care of interfacing with the
+	 * PHY to retrieve the desired data.
+	 */
+	i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
+	    (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
+	    (E1000_I2CCMD_OPCODE_READ));
+
+	E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd);
+
+	/* Poll the ready bit to see if the I2C read completed */
+	for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
+		usec_delay(50);
+		i2ccmd = E1000_READ_REG(hw, E1000_I2CCMD);
+		if (i2ccmd & E1000_I2CCMD_READY)
+			break;
+	}
+	if (!(i2ccmd & E1000_I2CCMD_READY)) {
+		DEBUGOUT("I2CCMD Read did not complete\n");
+		return (-E1000_ERR_PHY);
+	}
+	if (i2ccmd & E1000_I2CCMD_ERROR) {
+		DEBUGOUT("I2CCMD Error bit set\n");
+		return (-E1000_ERR_PHY);
+	}
+
+	/* Need to byte-swap the 16-bit value. */
+	*data = ((i2ccmd >> 8) & 0x00FF) | ((i2ccmd << 8) & 0xFF00);
+
+	return (E1000_SUCCESS);
+}
+
+/*
+ * e1000_write_phy_reg_i2c - Write PHY register using i2c
+ * @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 using the i2c interface.
+ */
+s32
+e1000_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 i, i2ccmd = 0;
+	u16 phy_data_swapped;
+
+	DEBUGFUNC("e1000_write_phy_reg_i2c");
+
+	/* Swap the data bytes for the I2C interface */
+	phy_data_swapped = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00);
+
+	/*
+	 * Set up Op-code, Phy Address, and register address in the I2CCMD
+	 * register.  The MAC will take care of interfacing with the
+	 * PHY to retrieve the desired data.
+	 */
+	i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
+	    (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
+	    E1000_I2CCMD_OPCODE_WRITE |
+	    phy_data_swapped);
+
+	E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd);
+
+	/* Poll the ready bit to see if the I2C read completed */
+	for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
+		usec_delay(50);
+		i2ccmd = E1000_READ_REG(hw, E1000_I2CCMD);
+		if (i2ccmd & E1000_I2CCMD_READY)
+			break;
+	}
+	if (!(i2ccmd & E1000_I2CCMD_READY)) {
+		DEBUGOUT("I2CCMD Write did not complete\n");
+		return (-E1000_ERR_PHY);
+	}
+	if (i2ccmd & E1000_I2CCMD_ERROR) {
+		DEBUGOUT("I2CCMD Error bit set\n");
+		return (-E1000_ERR_PHY);
+	}
+
+	return (E1000_SUCCESS);
+}
+
+/*
  * e1000_read_phy_reg_m88 - Read m88 PHY register
  * @hw: pointer to the HW structure
  * @offset: register offset to be read
@@ -393,42 +497,122 @@
 }
 
 /*
+ * __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
+ * @locked: semaphore has already been acquired or not
+ *
+ * Acquires semaphore, if necessary, then reads the PHY register at offset
+ * 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, if necessary, then reads the PHY register at offset
- * and storing the retrieved information in data.  Release any acquired
- * semaphores before exiting.
+ * 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;
-		}
+		if (ret_val)
+			goto release;
 	}
 
-	ret_val = e1000_read_phy_reg_mdic(hw,
+	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);
@@ -440,65 +624,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_read_kmrn_reg_generic - Read kumeran register
+ * 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 - 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.
  * 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_generic");
+
+	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;
@@ -509,43 +685,164 @@
 	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
+ *
+ * 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;
+	}
+
+	if (phy->type == e1000_phy_82580) {
+		ret_val = hw->phy.ops.reset(hw);
+		if (ret_val) {
+			DEBUGOUT("Error resetting the PHY.\n");
+			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);
@@ -811,7 +1108,7 @@
  * and restart the negotiation process between the link partner.  If
  * autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
  */
-s32
+static s32
 e1000_copper_link_autoneg(struct e1000_hw *hw)
 {
 	struct e1000_phy_info *phy = &hw->phy;
@@ -1743,9 +2040,8 @@
 			 * see if they have relinquished the resources yet.
 			 */
 			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)
@@ -1791,13 +2087,13 @@
 
 	index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
 	    M88E1000_PSSR_CABLE_LENGTH_SHIFT;
-	if (index < (M88E1000_CABLE_LENGTH_TABLE_SIZE + 1)) {
-		ret_val = E1000_ERR_PHY;
+	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->max_cable_length = e1000_m88_cable_length_table[index + 1];
 
 	phy->cable_length = (phy->min_cable_length +
 	    phy->max_cable_length) / 2;
@@ -1901,7 +2197,7 @@
 
 	DEBUGFUNC("e1000_get_phy_info_m88");
 
-	if (hw->phy.media_type != e1000_media_type_copper) {
+	if (phy->media_type != e1000_media_type_copper) {
 		DEBUGOUT("Phy info is only valid for copper media\n");
 		ret_val = -E1000_ERR_CONFIG;
 		goto out;
@@ -2004,7 +2300,7 @@
 
 	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
 	    IGP01E1000_PSSR_SPEED_1000MBPS) {
-		ret_val = hw->phy.ops.get_cable_length(hw);
+		ret_val = phy->ops.get_cable_length(hw);
 		if (ret_val)
 			goto out;
 
@@ -2245,6 +2541,9 @@
 	case IFE_C_E_PHY_ID:
 		phy_type = e1000_phy_ife;
 		break;
+	case I82580_I_PHY_ID:
+		phy_type = e1000_phy_82580;
+		break;
 	default:
 		phy_type = e1000_phy_unknown;
 		break;
@@ -2275,7 +2574,7 @@
 		i = 0;
 
 		do {
-			e1000_get_phy_id(hw);
+			(void) e1000_get_phy_id(hw);
 			phy_type = e1000_get_phy_type_from_id(hw->phy.id);
 
 			/*
@@ -2332,3 +2631,204 @@
 	(void) hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
 	msec_delay(1);
 }
+
+/*
+ * 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/igb/igb_phy.h	Mon Nov 23 12:45:18 2009 +0800
+++ b/usr/src/uts/common/io/igb/igb_phy.h	Mon Nov 23 14:27:01 2009 +0800
@@ -26,7 +26,7 @@
  * Use is subject to license terms of the CDDL.
  */
 
-/* IntelVersion: 1.69 v2-9-8_2009-6-12 */
+/* IntelVersion: 1.76 scm_100809_154340 */
 
 #ifndef _IGB_PHY_H
 #define	_IGB_PHY_H
@@ -45,7 +45,6 @@
 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);
@@ -62,13 +61,17 @@
 s32 e1000_phy_hw_reset_generic(struct e1000_hw *hw);
 s32 e1000_phy_reset_dsp_generic(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,
@@ -80,6 +83,13 @@
 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_i2c(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data);
+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
 
@@ -96,6 +106,36 @@
 #define	IGP_PAGE_SHIFT			5
 #define	PHY_REG_MASK			0x1F
 
+#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
+
 #define	IGP01E1000_PHY_PCS_INIT_REG	0x00B4
 #define	IGP01E1000_PHY_POLARITY_MASK	0x0078
 
--- a/usr/src/uts/common/io/igb/igb_regs.h	Mon Nov 23 12:45:18 2009 +0800
+++ b/usr/src/uts/common/io/igb/igb_regs.h	Mon Nov 23 14:27:01 2009 +0800
@@ -26,7 +26,7 @@
  * Use is subject to license terms of the CDDL.
  */
 
-/* IntelVersion: 1.70 v2-9-8_2009-6-12 */
+/* IntelVersion: 1.78 scm_100809_154340 */
 
 #ifndef _IGB_REGS_H
 #define	_IGB_REGS_H
@@ -43,6 +43,12 @@
 #define	E1000_CTRL_EXT	0x00018  /* Extended Device Control - RW */
 #define	E1000_FLA	0x0001C  /* Flash Access - RW */
 #define	E1000_MDIC	0x00020  /* MDI Control - RW */
+#define	E1000_MDICNFG	0x00E04  /* MDI Config - RW */
+#define	E1000_REGISTER_SET_SIZE		0x20000 /* CSR Size */
+#define	E1000_EEPROM_INIT_CTRL_WORD_2	0x0F /* EEPROM Init Ctrl Word 2 */
+#define	E1000_BARCTRL			0x5BBC /* BAR ctrl reg */
+#define	E1000_BARCTRL_FLSIZE		0x0700 /* BAR ctrl Flsize */
+#define	E1000_BARCTRL_CSRSIZE		0x2000 /* BAR ctrl CSR size */
 #define	E1000_SCTL	0x00024  /* SerDes Control - RW */
 #define	E1000_FCAL	0x00028  /* Flow Control Address Low - RW */
 #define	E1000_FCAH	0x0002C  /* Flow Control Address High -RW */
@@ -91,17 +97,19 @@
 #define	E1000_FLSWCNT	0x01038  /* FLASH Access Counter */
 #define	E1000_FLOP	0x0103C  /* FLASH Opcode Register */
 #define	E1000_I2CCMD	0x01028  /* SFPI2C Command Register - RW */
-#define	E1000_I2CPARAMS	0x0102C /* SFPI2C Parameters Register - RW */
+#define	E1000_I2CPARAMS	0x0102C  /* SFPI2C Parameters Register - RW */
 #define	E1000_WDSTP	0x01040  /* Watchdog Setup - RW */
 #define	E1000_SWDSTS	0x01044  /* SW Device Status - RW */
 #define	E1000_FRTIMER	0x01048  /* Free Running Timer - RW */
 #define	E1000_TCPTIMER	0x0104C  /* TCP Timer - RW */
 #define	E1000_VPDDIAG	0x01060  /* VPD Diagnostic - RO */
-#define	E1000_ICR_V2 0x01500  /* Interrupt Cause - new location - RC */
-#define	E1000_ICS_V2 0x01504  /* Interrupt Cause Set - new location - WO */
-#define	E1000_IMS_V2 0x01508  /* Interrupt Mask Set/Read - new location - RW */
-#define	E1000_IMC_V2 0x0150C  /* Interrupt Mask Clear - new location - WO */
-#define	E1000_IAM_V2 0x01510  /* Interrupt Ack Auto Mask - new location - RW */
+#define	E1000_ICR_V2	0x01500  /* Interrupt Cause - new location - RC */
+#define	E1000_ICS_V2	0x01504  /* Interrupt Cause Set - new location - WO */
+/* Interrupt Mask Set/Read - new location - RW */
+#define	E1000_IMS_V2	0x01508
+#define	E1000_IMC_V2	0x0150C  /* Interrupt Mask Clear - new location - WO */
+/* Interrupt Ack Auto Mask - new location - RW */
+#define	E1000_IAM_V2	0x01510
 #define	E1000_ERT	0x02008  /* Early Rx Threshold - RW */
 #define	E1000_FCRTL	0x02160  /* Flow Control Receive Threshold Low - RW */
 #define	E1000_FCRTH	0x02168  /* Flow Control Receive Threshold High - RW */
@@ -117,11 +125,8 @@
 #define	E1000_RDPUCTL	0x025DC  /* DMA Rx Descriptor uC Control - RW */
 #define	E1000_PBDIAG	0x02458  /* Packet Buffer Diagnostic - RW */
 #define	E1000_RXPBS	0x02404  /* Rx Packet Buffer Size - RW */
-#define	E1000_RXCTL(_n)	(0x0C014 + (0x40 * (_n)))
-#define	E1000_RQDPC(_n)	(0x0C030 + (0x40 * (_n)))
-#define	E1000_TXCTL(_n)	(0x0E014 + (0x40 * (_n)))
-#define	E1000_RXCTL(_n)	(0x0C014 + (0x40 * (_n)))
-#define	E1000_RQDPC(_n)	(0x0C030 + (0x40 * (_n)))
+/* Same as RXPBS, renamed for newer adapters - RW */
+#define	E1000_IRPBS	0x02404
 #define	E1000_RDTR	0x02820  /* Rx Delay Timer - RW */
 #define	E1000_RADV	0x0282C  /* Rx Interrupt Absolute Delay Timer - RW */
 /*
@@ -147,12 +152,19 @@
 #define	E1000_RDH(_n)		((_n) < 4 ?	\
 	(0x02810 + ((_n) * 0x100)) :	\
 	(0x0C010 + ((_n) * 0x40)))
+#define	E1000_RXCTL(_n)		((_n) < 4 ?	\
+	(0x02814 + ((_n) * 0x100)) :	\
+	(0x0C014 + ((_n) * 0x40)))
+#define	E1000_DCA_RXCTRL(_n)	E1000_RXCTL(_n)
 #define	E1000_RDT(_n)		((_n) < 4 ?	\
 	(0x02818 + ((_n) * 0x100)) :	\
 	(0x0C018 + ((_n) * 0x40)))
 #define	E1000_RXDCTL(_n)	((_n) < 4 ?	\
 	(0x02828 + ((_n) * 0x100)) :	\
 	(0x0C028 + ((_n) * 0x40)))
+#define	E1000_RQDPC(_n)		((_n) < 4 ?	\
+	(0x02830 + ((_n) * 0x100)) :	\
+	(0x0C030 + ((_n) * 0x40)))
 #define	E1000_TDBAL(_n)		((_n) < 4 ?	\
 	(0x03800 + ((_n) * 0x100)) :	\
 	(0x0E000 + ((_n) * 0x40)))
@@ -165,21 +177,23 @@
 #define	E1000_TDH(_n)		((_n) < 4 ?	\
 	(0x03810 + ((_n) * 0x100)) :	\
 	(0x0E010 + ((_n) * 0x40)))
+#define	E1000_TXCTL(_n)		((_n) < 4 ?	\
+	(0x03814 + ((_n) * 0x100)) :	\
+	(0x0E014 + ((_n) * 0x40)))
+#define	E1000_DCA_TXCTRL(_n)	E1000_TXCTL(_n)
 #define	E1000_TDT(_n)		((_n) < 4 ?	\
 	(0x03818 + ((_n) * 0x100)) :	\
 	(0x0E018 + ((_n) * 0x40)))
 #define	E1000_TXDCTL(_n)	((_n) < 4 ?	\
 	(0x03828 + ((_n) * 0x100)) :	\
 	(0x0E028 + ((_n) * 0x40)))
-#define	E1000_TARC(_n)		(0x03840 + (_n << 8))
-#define	E1000_DCA_TXCTRL(_n)	(0x03814 + (_n << 8))
-#define	E1000_DCA_RXCTRL(_n)	(0x02814 + (_n << 8))
 #define	E1000_TDWBAL(_n)	((_n) < 4 ?	\
 	(0x03838 + ((_n) * 0x100)) :	\
 	(0x0E038 + ((_n) * 0x40)))
 #define	E1000_TDWBAH(_n)	((_n) < 4 ?	\
 	(0x0383C + ((_n) * 0x100)) :	\
 	(0x0E03C + ((_n) * 0x40)))
+#define	E1000_TARC(_n)		(0x03840 + ((_n) * 0x100))
 #define	E1000_RSRPD	0x02C00  /* Rx Small Packet Detect - RW */
 #define	E1000_RAID	0x02C08  /* Receive Ack Interrupt Delay - RW */
 #define	E1000_TXDMAC	0x03000  /* Tx DMA Control - RW */
@@ -201,6 +215,8 @@
 /* Packet Buffer DWORD (_n) */
 #define	E1000_PBSLAD(_n)	(0x03110 + (0x4 * (_n)))
 #define	E1000_TXPBS	0x03404  /* Tx Packet Buffer Size - RW */
+/* Same as TXPBS, renamed for newer adpaters - RW */
+#define	E1000_ITPBS	0x03404
 #define	E1000_TDFH	0x03410  /* Tx Data FIFO Head - RW */
 #define	E1000_TDFT	0x03418  /* Tx Data FIFO Tail - RW */
 #define	E1000_TDFHS	0x03420  /* Tx Data FIFO Head Saved - RW */
@@ -539,6 +555,15 @@
 #define	E1000_RTTBCNACH	0x0B214 /* Tx BCN Control High */
 #define	E1000_RTTBCNACL	0x0B210 /* Tx BCN Control Low */
 
+/* DMA Coalescing registers */
+#define	E1000_DMACR	0x02508 /* Control Register */
+#define	E1000_DMCTXTH	0x03550 /* Transmit Threshold */
+#define	E1000_DMCTLX	0x02514 /* Time to Lx Request */
+#define	E1000_DMCRTRH	0x05DD0 /* Receive Packet Rate Threshold */
+#define	E1000_DMCCNT	0x05DD4 /* Current RX Count */
+#define	E1000_FCRTC	0x02170 /* Flow Control Rx high watermark */
+#define	E1000_PCIEMISC	0x05BB8 /* PCIE misc config register */
+
 #ifdef __cplusplus
 }
 #endif
--- a/usr/src/uts/common/io/igb/igb_sw.h	Mon Nov 23 12:45:18 2009 +0800
+++ b/usr/src/uts/common/io/igb/igb_sw.h	Mon Nov 23 14:27:01 2009 +0800
@@ -81,6 +81,7 @@
 #define	IGB_INITIALIZED			0x01
 #define	IGB_STARTED			0x02
 #define	IGB_SUSPENDED			0x04
+#define	IGB_STALL			0x08
 
 #define	IGB_INTR_NONE			0
 #define	IGB_INTR_MSIX			1
@@ -114,10 +115,6 @@
 
 #define	MAX_MTU				9000
 #define	MAX_RX_LIMIT_PER_INTR		4096
-#define	MAX_RX_INTR_DELAY		65535
-#define	MAX_RX_INTR_ABS_DELAY		65535
-#define	MAX_TX_INTR_DELAY		65535
-#define	MAX_TX_INTR_ABS_DELAY		65535
 
 #define	MAX_RX_COPY_THRESHOLD		9216
 #define	MAX_TX_COPY_THRESHOLD		9216
@@ -135,10 +132,7 @@
 
 #define	MIN_MTU				ETHERMIN
 #define	MIN_RX_LIMIT_PER_INTR		16
-#define	MIN_RX_INTR_DELAY		0
-#define	MIN_RX_INTR_ABS_DELAY		0
-#define	MIN_TX_INTR_DELAY		0
-#define	MIN_TX_INTR_ABS_DELAY		0
+
 #define	MIN_RX_COPY_THRESHOLD		0
 #define	MIN_TX_COPY_THRESHOLD		0
 #define	MIN_TX_RECYCLE_THRESHOLD	MIN_NUM_TX_DESC
@@ -155,10 +149,7 @@
 
 #define	DEFAULT_MTU			ETHERMTU
 #define	DEFAULT_RX_LIMIT_PER_INTR	256
-#define	DEFAULT_RX_INTR_DELAY		0
-#define	DEFAULT_RX_INTR_ABS_DELAY	0
-#define	DEFAULT_TX_INTR_DELAY		300
-#define	DEFAULT_TX_INTR_ABS_DELAY	0
+
 #define	DEFAULT_RX_COPY_THRESHOLD	128
 #define	DEFAULT_TX_COPY_THRESHOLD	512
 #define	DEFAULT_TX_RECYCLE_THRESHOLD	(MAX_COOKIE + 1)
@@ -834,8 +825,8 @@
 void e1000_read_pci_cfg(struct e1000_hw *, uint32_t, uint16_t *);
 int32_t e1000_read_pcie_cap_reg(struct e1000_hw *, uint32_t, uint16_t *);
 int32_t e1000_write_pcie_cap_reg(struct e1000_hw *, uint32_t, uint16_t *);
-void e1000_rar_clear(struct e1000_hw *hw, uint32_t);
-void e1000_rar_set_vmdq(struct e1000_hw *hw, const uint8_t *, uint32_t,
+void e1000_rar_clear(struct e1000_hw *, uint32_t);
+void e1000_rar_set_vmdq(struct e1000_hw *, const uint8_t *, uint32_t,
     uint32_t, uint8_t);
 
 /*
--- a/usr/src/uts/common/io/igb/igb_tx.c	Mon Nov 23 12:45:18 2009 +0800
+++ b/usr/src/uts/common/io/igb/igb_tx.c	Mon Nov 23 14:27:01 2009 +0800
@@ -957,7 +957,7 @@
 		    (mbsize - ctx->mac_hdr_len - ctx->ip_hdr_len
 		    - ctx->l4_hdr_len) << E1000_ADVTXD_PAYLEN_SHIFT;
 	} else {
-		if (hw->mac.type == e1000_82576) {
+		if (hw->mac.type >= e1000_82576) {
 			first_tbd->read.olinfo_status |=
 			    (mbsize << E1000_ADVTXD_PAYLEN_SHIFT);
 		}