changeset 13599:b51e5a82e5e2

2038 Add in I350 and ET2 support into igb Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com> Reviewed by: Dan McDonald <danmcd@nexenta.com> Reviewed by: Gordon Ross <gwr@nexenta.com> Reviewed by: Garrett D'Amore <garrett@damore.org> Approved by: Albert Lee <trisk@nexenta.com>
author Robert Mustacchi <rm@joyent.com>
date Mon, 06 Feb 2012 13:23:22 -0500
parents 9db0a4a7c636
children 45e723c4523d
files usr/src/pkg/manifests/driver-network-igb.mf 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_defines.h usr/src/uts/common/io/igb/igb_hw.h usr/src/uts/common/io/igb/igb_main.c usr/src/uts/common/io/igb/igb_regs.h
diffstat 8 files changed, 362 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/pkg/manifests/driver-network-igb.mf	Mon Feb 06 12:07:49 2012 -0800
+++ b/usr/src/pkg/manifests/driver-network-igb.mf	Mon Feb 06 13:23:22 2012 -0500
@@ -21,6 +21,7 @@
 
 #
 # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2012, Nexenta Systems, Inc. All rights reserved.
 #
 
 #
@@ -55,7 +56,9 @@
     alias=pciex8086,1510 \
     alias=pciex8086,1511 \
     alias=pciex8086,1516 \
-    alias=pciex8086,1518
+    alias=pciex8086,1518 \
+    alias=pciex8086,1521 \
+    alias=pciex8086,1526
 file path=kernel/drv/$(ARCH64)/igb group=sys
 $(i386_ONLY)file path=kernel/drv/igb group=sys
 file path=kernel/drv/igb.conf group=sys \
--- a/usr/src/uts/common/io/igb/igb_82575.c	Mon Feb 06 12:07:49 2012 -0800
+++ b/usr/src/uts/common/io/igb/igb_82575.c	Mon Feb 06 13:23:22 2012 -0500
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright(c) 2007-2010 Intel Corporation. All rights reserved.
+ * Copyright (c) 2007-2012 Intel Corporation. All rights reserved.
  */
 
 /*
@@ -80,6 +80,15 @@
 static void e1000_shutdown_serdes_link_82575(struct e1000_hw *hw);
 static s32 e1000_set_pcie_completion_timeout(struct e1000_hw *hw);
 
+static s32 e1000_update_nvm_checksum_with_offset(struct e1000_hw *hw,
+    u16 offset);
+static s32 e1000_validate_nvm_checksum_with_offset(struct e1000_hw *hw,
+    u16 offset);
+static s32 e1000_validate_nvm_checksum_i350(struct e1000_hw *hw);
+static s32 e1000_update_nvm_checksum_i350(struct e1000_hw *hw);
+static void e1000_write_vfta_i350(struct e1000_hw *hw, u32 offset, u32 value);
+static void e1000_clear_vfta_i350(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 \
@@ -151,6 +160,7 @@
 		phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_generic;
 		break;
 	case I82580_I_PHY_ID:
+	case I350_I_PHY_ID:
 		phy->type = e1000_phy_82580;
 		phy->ops.check_polarity = e1000_check_polarity_82577;
 		phy->ops.force_speed_duplex =
@@ -222,6 +232,17 @@
 	nvm->ops.validate = e1000_validate_nvm_checksum_generic;
 	nvm->ops.write = e1000_write_nvm_spi;
 
+	/* override genric family function pointers for specific descendants */
+	switch (hw->mac.type) {
+	case e1000_i350:
+		nvm->ops.validate = e1000_validate_nvm_checksum_i350;
+		nvm->ops.update = e1000_update_nvm_checksum_i350;
+		break;
+	default:
+		break;
+	}
+
+
 	return (E1000_SUCCESS);
 }
 
@@ -284,6 +305,11 @@
 		mac->rar_entry_count = E1000_RAR_ENTRIES_82576;
 	if (mac->type == e1000_82580)
 		mac->rar_entry_count = E1000_RAR_ENTRIES_82580;
+	if (mac->type == e1000_i350) {
+		mac->rar_entry_count = E1000_RAR_ENTRIES_I350;
+		/* Enable EEE default settings for i350 */
+		dev_spec->eee_disable = B_FALSE;
+	}
 	/* Set if part includes ASF firmware */
 	mac->asf_firmware_present = true;
 	/* Set if manageability features are enabled. */
@@ -319,10 +345,18 @@
 	mac->ops.read_mac_addr = e1000_read_mac_addr_82575;
 	/* multicast address update */
 	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
-	/* writing VFTA */
-	mac->ops.write_vfta = e1000_write_vfta_generic;
-	/* clearing VFTA */
-	mac->ops.clear_vfta = e1000_clear_vfta_generic;
+
+	if (hw->mac.type == e1000_i350) {
+		/* writing VFTA */
+		mac->ops.write_vfta = e1000_write_vfta_i350;
+		/* clearing VFTA */
+		mac->ops.clear_vfta = e1000_clear_vfta_i350;
+	} else {
+		/* writing VFTA */
+		mac->ops.write_vfta = e1000_write_vfta_generic;
+		/* clearing VFTA */
+		mac->ops.clear_vfta = e1000_clear_vfta_generic;
+	}
 	/* setting MTA */
 	mac->ops.mta_set = e1000_mta_set_generic;
 	/* ID LED init */
@@ -697,6 +731,22 @@
 	if (ret_val)
 		goto out;
 
+	/*
+	 * Check if there is some access
+	 * error this access may hook on
+	 */
+	if (hw->mac.type == e1000_i350) {
+		u32 eecd = E1000_READ_REG(hw, E1000_EECD);
+		if (eecd & (E1000_EECD_BLOCKED | E1000_EECD_ABORT |
+		    E1000_EECD_TIMEOUT)) {
+			/* Clear all access error flags */
+			E1000_WRITE_REG(hw, E1000_EECD, eecd |
+			    E1000_EECD_ERROR_CLR);
+			DEBUGOUT("Nvm bit banging access error "
+			    "detected and cleared.\n");
+		}
+	}
+
 	ret_val = e1000_acquire_nvm_generic(hw);
 
 	if (ret_val)
@@ -1866,3 +1916,229 @@
 
 	return (ret_val);
 }
+
+/*
+ * Due to a hw errata, if the host tries to  configure the VFTA register
+ * while performing queries from the BMC or DMA, then the VFTA in some
+ * cases won't be written.
+ */
+
+/*
+ *  e1000_clear_vfta_i350 - Clear VLAN filter table
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the register array which contains the VLAN filter table by
+ *  setting all the values to 0.
+ */
+void
+e1000_clear_vfta_i350(struct e1000_hw *hw)
+{
+	u32 offset;
+	int i;
+
+	DEBUGFUNC("e1000_clear_vfta_350");
+
+	for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
+		for (i = 0; i < 10; i++)
+			E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, 0);
+
+		E1000_WRITE_FLUSH(hw);
+	}
+}
+
+/*
+ *  e1000_write_vfta_i350 - Write value to VLAN filter table
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset in VLAN filter table
+ *  @value: register value written to VLAN filter table
+ *
+ *  Writes value at the given offset in the register array which stores
+ *  the VLAN filter table.
+ */
+void
+e1000_write_vfta_i350(struct e1000_hw *hw, u32 offset, u32 value)
+{
+	int i;
+
+	DEBUGFUNC("e1000_write_vfta_350");
+
+	for (i = 0; i < 10; i++)
+		E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value);
+
+	E1000_WRITE_FLUSH(hw);
+}
+
+/*
+ *  e1000_validate_nvm_checksum_with_offset - Validate EEPROM
+ *  checksum
+ *  @hw: pointer to the HW structure
+ *  @offset: offset in words of the checksum protected region
+ *
+ *  Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ */
+s32
+e1000_validate_nvm_checksum_with_offset(struct e1000_hw *hw, u16 offset)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 checksum = 0;
+	u16 i, nvm_data;
+
+	DEBUGFUNC("e1000_validate_nvm_checksum_with_offset");
+
+	for (i = offset; i < ((NVM_CHECKSUM_REG + offset) + 1); i++) {
+		ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
+		if (ret_val) {
+			DEBUGOUT("NVM Read Error\n");
+			goto out;
+		}
+		checksum += nvm_data;
+	}
+
+	if (checksum != (u16) NVM_SUM) {
+		DEBUGOUT("NVM Checksum Invalid\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+out:
+	return (ret_val);
+}
+
+/*
+ *  e1000_update_nvm_checksum_with_offset - Update EEPROM
+ *  checksum
+ *  @hw: pointer to the HW structure
+ *  @offset: offset in words of the checksum protected region
+ *
+ *  Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  up to the checksum.  Then calculates the EEPROM checksum and writes the
+ *  value to the EEPROM.
+ */
+s32
+e1000_update_nvm_checksum_with_offset(struct e1000_hw *hw, u16 offset)
+{
+	s32 ret_val;
+	u16 checksum = 0;
+	u16 i, nvm_data;
+
+	DEBUGFUNC("e1000_update_nvm_checksum_with_offset");
+
+	for (i = offset; i < (NVM_CHECKSUM_REG + offset); i++) {
+		ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
+		if (ret_val) {
+			DEBUGOUT("NVM Read Error while updating checksum.\n");
+			goto out;
+		}
+		checksum += nvm_data;
+	}
+	checksum = (u16) NVM_SUM - checksum;
+	ret_val = hw->nvm.ops.write(hw, (NVM_CHECKSUM_REG + offset), 1,
+	    &checksum);
+	if (ret_val)
+		DEBUGOUT("NVM Write Error while updating checksum.\n");
+
+out:
+	return (ret_val);
+}
+
+/*
+ *  e1000_validate_nvm_checksum_i350 - Validate EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Calculates the EEPROM section checksum by reading/adding each word of
+ *  the EEPROM and then verifies that the sum of the EEPROM is
+ *  equal to 0xBABA.
+ */
+static s32
+e1000_validate_nvm_checksum_i350(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 j;
+	u16 nvm_offset;
+
+	DEBUGFUNC("e1000_validate_nvm_checksum_i350");
+
+	for (j = 0; j < 4; j++) {
+		nvm_offset = NVM_82580_LAN_FUNC_OFFSET(j);
+		ret_val = e1000_validate_nvm_checksum_with_offset(hw,
+		    nvm_offset);
+		if (ret_val != E1000_SUCCESS)
+			goto out;
+	}
+
+out:
+	return (ret_val);
+}
+
+/*
+ *  e1000_update_nvm_checksum_i350 - Update EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Updates the EEPROM section checksums for all 4 ports by reading/adding
+ *  each word of the EEPROM up to the checksum.  Then calculates the EEPROM
+ *  checksum and writes the value to the EEPROM.
+ */
+static s32
+e1000_update_nvm_checksum_i350(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 j;
+	u16 nvm_offset;
+
+	DEBUGFUNC("e1000_update_nvm_checksum_i350");
+
+	for (j = 0; j < 4; j++) {
+		nvm_offset = NVM_82580_LAN_FUNC_OFFSET(j);
+		ret_val = e1000_update_nvm_checksum_with_offset(hw, nvm_offset);
+		if (ret_val != E1000_SUCCESS)
+			goto out;
+	}
+
+out:
+	return (ret_val);
+}
+
+
+
+/*
+ *  e1000_set_eee_i350 - Enable/disable EEE support
+ *  @hw: pointer to the HW structure
+ *
+ *  Enable/disable EEE based on setting in dev_spec structure.
+ *
+ */
+s32
+e1000_set_eee_i350(struct e1000_hw *hw)
+{
+
+	s32 ret_val = E1000_SUCCESS;
+	u32 ipcnfg, eeer;
+
+	DEBUGFUNC("e1000_set_eee_i350");
+
+	if ((hw->mac.type < e1000_i350) ||
+	    (hw->phy.media_type != e1000_media_type_copper))
+		goto out;
+	ipcnfg = E1000_READ_REG(hw, E1000_IPCNFG);
+	eeer = E1000_READ_REG(hw, E1000_EEER);
+
+	/* enable or disable per user setting */
+	if (!(hw->dev_spec._82575.eee_disable)) {
+		ipcnfg |= (E1000_IPCNFG_EEE_1G_AN | E1000_IPCNFG_EEE_100M_AN);
+		eeer |= (E1000_EEER_TX_LPI_EN | E1000_EEER_RX_LPI_EN |
+		    E1000_EEER_LPI_FC);
+
+	} else {
+		ipcnfg &= ~(E1000_IPCNFG_EEE_1G_AN | E1000_IPCNFG_EEE_100M_AN);
+		eeer &= ~(E1000_EEER_TX_LPI_EN | E1000_EEER_RX_LPI_EN |
+		    E1000_EEER_LPI_FC);
+	}
+	E1000_WRITE_REG(hw, E1000_IPCNFG, ipcnfg);
+	E1000_WRITE_REG(hw, E1000_EEER, eeer);
+	ipcnfg = E1000_READ_REG(hw, E1000_IPCNFG);
+	eeer = E1000_READ_REG(hw, E1000_EEER);
+out:
+
+	return (ret_val);
+}
--- a/usr/src/uts/common/io/igb/igb_82575.h	Mon Feb 06 12:07:49 2012 -0800
+++ b/usr/src/uts/common/io/igb/igb_82575.h	Mon Feb 06 13:23:22 2012 -0500
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright(c) 2007-2010 Intel Corporation. All rights reserved.
+ * Copyright (c) 2007-2012 Intel Corporation. All rights reserved.
  */
 
 /*
@@ -54,6 +54,7 @@
 #define	E1000_RAR_ENTRIES_82575		16
 #define	E1000_RAR_ENTRIES_82576		24
 #define	E1000_RAR_ENTRIES_82580		24
+#define	E1000_RAR_ENTRIES_I350		32
 #define	E1000_SW_SYNCH_MB		0x00000100
 #define	E1000_STAT_DEV_RST_SET		0x00100000
 #define	E1000_CTRL_DEV_RST		0x20000000
@@ -466,6 +467,7 @@
 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);
+s32 e1000_set_eee_i350(struct e1000_hw *hw);
 
 #ifdef __cplusplus
 }
--- a/usr/src/uts/common/io/igb/igb_api.c	Mon Feb 06 12:07:49 2012 -0800
+++ b/usr/src/uts/common/io/igb/igb_api.c	Mon Feb 06 13:23:22 2012 -0500
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright(c) 2007-2010 Intel Corporation. All rights reserved.
+ * Copyright (c) 2007-2012 Intel Corporation. All rights reserved.
  */
 
 /*
@@ -139,6 +139,7 @@
 	case E1000_DEV_ID_82576_FIBER:
 	case E1000_DEV_ID_82576_SERDES:
 	case E1000_DEV_ID_82576_QUAD_COPPER:
+	case E1000_DEV_ID_82576_QUAD_COPPER_ET2:
 	case E1000_DEV_ID_82576_NS:
 	case E1000_DEV_ID_82576_NS_SERDES:
 	case E1000_DEV_ID_82576_SERDES_QUAD:
@@ -151,6 +152,9 @@
 	case E1000_DEV_ID_82580_COPPER_DUAL:
 		mac->type = e1000_82580;
 		break;
+	case E1000_DEV_ID_I350_COPPER:
+		mac->type = e1000_i350;
+		break;
 	default:
 		/* Should never have loaded on this device */
 		ret_val = -E1000_ERR_MAC_INIT;
@@ -207,6 +211,7 @@
 	case e1000_82575:
 	case e1000_82576:
 	case e1000_82580:
+	case e1000_i350:
 		e1000_init_function_pointers_82575(hw);
 		break;
 	default:
--- a/usr/src/uts/common/io/igb/igb_defines.h	Mon Feb 06 12:07:49 2012 -0800
+++ b/usr/src/uts/common/io/igb/igb_defines.h	Mon Feb 06 13:23:22 2012 -0500
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright(c) 2007-2010 Intel Corporation. All rights reserved.
+ * Copyright (c) 2007-2012 Intel Corporation. All rights reserved.
  */
 
 /*
@@ -1007,6 +1007,14 @@
 #define	E1000_IMIR_PRIORITY_SHIFT	29 /* IMIR Priority Shift */
 #define	E1000_IMIREXT_CLEAR_MASK	0x7FFFF /* IMIREXT Reg Clear Mask */
 
+/* I350 EEE defines */
+#define	E1000_IPCNFG_EEE_1G_AN		0x00000008 /* IPCNFG EEE Ena 1G AN */
+#define	E1000_IPCNFG_EEE_100M_AN	0x00000004 /* IPCNFG EEE Ena 100M AN */
+#define	E1000_EEER_TX_LPI_EN		0x00010000 /* EEER Tx LPI Enable */
+#define	E1000_EEER_RX_LPI_EN		0x00020000 /* EEER Rx LPI Enable */
+#define	E1000_EEER_LPI_FC		0x00040000 /* EEER Ena on Flow Cntrl */
+
+
 /* PCI Express Control */
 #define	E1000_GCR_RXD_NO_SNOOP		0x00000001
 #define	E1000_GCR_RXDSCW_NO_SNOOP	0x00000002
@@ -1148,6 +1156,11 @@
 #define	E1000_EECD_GNT		0x00000080 /* NVM Access Grant */
 #define	E1000_EECD_PRES		0x00000100 /* NVM Present */
 #define	E1000_EECD_SIZE		0x00000200 /* NVM Size (0=64 word 1=256 word) */
+#define	E1000_EECD_BLOCKED	0x00008000 /* Bit banging access blocked flag */
+#define	E1000_EECD_ABORT	0x00010000 /* NVM operation aborted flag */
+#define	E1000_EECD_TIMEOUT	0x00020000 /* NVM read operation timeout flag */
+#define	E1000_EECD_ERROR_CLR	0x00040000 /* NVM error status clear bit */
+
 /* NVM Addressing bits based on type 0=small, 1=large */
 #define	E1000_EECD_ADDR_BITS	0x00000400
 #define	E1000_EECD_TYPE		0x00002000 /* NVM Type (1-SPI, 0-Microwire) */
@@ -1307,6 +1320,7 @@
 #define	IFE_PLUS_E_PHY_ID	0x02A80320
 #define	IFE_C_E_PHY_ID		0x02A80310
 #define	I82580_I_PHY_ID		0x015403A0
+#define	I350_I_PHY_ID		0x015403B0
 #define	IGP04E1000_E_PHY_ID	0x02A80391
 #define	M88_VENDOR		0x0141
 
--- a/usr/src/uts/common/io/igb/igb_hw.h	Mon Feb 06 12:07:49 2012 -0800
+++ b/usr/src/uts/common/io/igb/igb_hw.h	Mon Feb 06 13:23:22 2012 -0500
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright(c) 2007-2010 Intel Corporation. All rights reserved.
+ * Copyright (c) 2007-2012 Intel Corporation. All rights reserved.
  */
 
 /*
@@ -46,6 +46,7 @@
 #define	E1000_DEV_ID_82576_FIBER		0x10E6
 #define	E1000_DEV_ID_82576_SERDES		0x10E7
 #define	E1000_DEV_ID_82576_QUAD_COPPER		0x10E8
+#define	E1000_DEV_ID_82576_QUAD_COPPER_ET2	0x1526
 #define	E1000_DEV_ID_82576_NS			0x150A
 #define	E1000_DEV_ID_82576_NS_SERDES		0x1518
 #define	E1000_DEV_ID_82576_SERDES_QUAD		0x150D
@@ -57,6 +58,7 @@
 #define	E1000_DEV_ID_82580_SERDES		0x1510
 #define	E1000_DEV_ID_82580_SGMII		0x1511
 #define	E1000_DEV_ID_82580_COPPER_DUAL		0x1516
+#define	E1000_DEV_ID_I350_COPPER		0x1521
 
 #define	E1000_REVISION_0 0
 #define	E1000_REVISION_1 1
@@ -79,6 +81,7 @@
 	e1000_82575,
 	e1000_82576,
 	e1000_82580,
+	e1000_i350,
 	e1000_num_macs  /* List is 1-based, so subtract 1 for true count. */
 };
 
@@ -640,6 +643,7 @@
 struct e1000_dev_spec_82575 {
 	bool sgmii_active;
 	bool global_device_reset;
+	int eee_disable;
 };
 
 struct e1000_dev_spec_vf {
--- a/usr/src/uts/common/io/igb/igb_main.c	Mon Feb 06 12:07:49 2012 -0800
+++ b/usr/src/uts/common/io/igb/igb_main.c	Mon Feb 06 13:23:22 2012 -0500
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright(c) 2007-2010 Intel Corporation. All rights reserved.
+ * Copyright (c) 2007-2012 Intel Corporation. All rights reserved.
  */
 
 /*
@@ -30,7 +30,7 @@
 #include "igb_sw.h"
 
 static char ident[] = "Intel 1Gb Ethernet";
-static char igb_version[] = "igb 1.1.17";
+static char igb_version[] = "igb 1.1.18";
 
 /*
  * Local function protoypes
@@ -285,6 +285,30 @@
 	0xffe00000		/* mask for RXDCTL register */
 };
 
+static adapter_info_t igb_i350_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
  */
@@ -517,6 +541,13 @@
 	igb_log(igb, "%s", igb_version);
 	atomic_or_32(&igb->igb_state, IGB_INITIALIZED);
 
+	/*
+	 * Newer models have Energy Efficient Ethernet, let's disable this by
+	 * default.
+	 */
+	if (igb->hw.mac.type == e1000_i350)
+		(void) e1000_set_eee_i350(&igb->hw);
+
 	return (DDI_SUCCESS);
 
 attach_fail:
@@ -836,6 +867,9 @@
 	case e1000_82580:
 		igb->capab = &igb_82580_cap;
 		break;
+	case e1000_i350:
+		igb->capab = &igb_i350_cap;
+		break;
 	default:
 		return (IGB_FAILURE);
 	}
@@ -1699,6 +1733,9 @@
 	if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK)
 		goto start_failure;
 
+	if (igb->hw.mac.type == e1000_i350)
+		(void) e1000_set_eee_i350(&igb->hw);
+
 	for (i = igb->num_tx_rings - 1; i >= 0; i--)
 		mutex_exit(&igb->tx_rings[i].tx_lock);
 	for (i = igb->num_rx_rings - 1; i >= 0; i--)
--- a/usr/src/uts/common/io/igb/igb_regs.h	Mon Feb 06 12:07:49 2012 -0800
+++ b/usr/src/uts/common/io/igb/igb_regs.h	Mon Feb 06 13:23:22 2012 -0500
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright(c) 2007-2010 Intel Corporation. All rights reserved.
+ * Copyright (c) 2007-2012 Intel Corporation. All rights reserved.
  */
 
 /*
@@ -570,6 +570,14 @@
 /* PCIe Parity Status Register */
 #define	E1000_PCIEERRSTS	0x05BA8
 
+/* Energy Efficient Ethernet "EEE" registers */
+#define	E1000_IPCNFG	0x0E38 /* Internal PHY Configuration */
+#define	E1000_LTRC	0x01A0 /* Latency Tolerance Reporting Control */
+#define	E1000_EEER	0x0E30 /* Energy Efficient Ethernet "EEE" */
+#define	E1000_EEE_SU	0x0E34 /* EEE Setup */
+#define	E1000_TLPIC	0x4148 /* EEE Tx LPI Count - TLPIC */
+#define	E1000_RLPIC	0x414C /* EEE Rx LPI Count - RLPIC */
+
 #ifdef __cplusplus
 }
 #endif