netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [UPDATED PATCH] e1000e: add support for new 82574L part
@ 2008-08-13  7:30 Jeff Kirsher
  2008-08-13 15:29 ` Arthur Jones
  0 siblings, 1 reply; 3+ messages in thread
From: Jeff Kirsher @ 2008-08-13  7:30 UTC (permalink / raw)
  To: jeff; +Cc: netdev, akpm, Bruce Allan, Jeff Kirsher

From: Bruce Allan <bruce.w.allan@intel.com>

This new part has the same feature set as previous parts with the addition
of MSI-X support.

Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---

 drivers/net/e1000e/82571.c   |  153 ++++++++++++++--
 drivers/net/e1000e/defines.h |   13 +
 drivers/net/e1000e/e1000.h   |   28 +++
 drivers/net/e1000e/es2lan.c  |    2 
 drivers/net/e1000e/ethtool.c |   38 +++-
 drivers/net/e1000e/hw.h      |   11 +
 drivers/net/e1000e/ich8lan.c |   18 ++
 drivers/net/e1000e/lib.c     |    7 -
 drivers/net/e1000e/netdev.c  |  409 +++++++++++++++++++++++++++++++++++++-----
 drivers/net/e1000e/param.c   |   27 +++
 drivers/net/e1000e/phy.c     |  109 +++++++++++
 11 files changed, 738 insertions(+), 77 deletions(-)

diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c
index 462351c..b2c910c 100644
--- a/drivers/net/e1000e/82571.c
+++ b/drivers/net/e1000e/82571.c
@@ -38,6 +38,7 @@
  * 82573V Gigabit Ethernet Controller (Copper)
  * 82573E Gigabit Ethernet Controller (Copper)
  * 82573L Gigabit Ethernet Controller
+ * 82574L Gigabit Network Connection
  */
 
 #include <linux/netdevice.h>
@@ -54,6 +55,8 @@
 
 #define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
 
+#define E1000_NVM_INIT_CTRL2_MNGM 0x6000 /* Manageability Operation Mode mask */
+
 static s32 e1000_get_phy_id_82571(struct e1000_hw *hw);
 static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw);
 static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw);
@@ -63,6 +66,8 @@ static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw);
 static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw);
 static s32 e1000_setup_link_82571(struct e1000_hw *hw);
 static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw);
+static bool e1000_check_mng_mode_82574(struct e1000_hw *hw);
+static s32 e1000_led_on_82574(struct e1000_hw *hw);
 
 /**
  *  e1000_init_phy_params_82571 - Init PHY func ptrs.
@@ -92,6 +97,9 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
 	case e1000_82573:
 		phy->type		 = e1000_phy_m88;
 		break;
+	case e1000_82574:
+		phy->type		 = e1000_phy_bm;
+		break;
 	default:
 		return -E1000_ERR_PHY;
 		break;
@@ -111,6 +119,10 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
 		if (phy->id != M88E1111_I_PHY_ID)
 			return -E1000_ERR_PHY;
 		break;
+	case e1000_82574:
+		if (phy->id != BME1000_E_PHY_ID_R2)
+			return -E1000_ERR_PHY;
+		break;
 	default:
 		return -E1000_ERR_PHY;
 		break;
@@ -150,6 +162,7 @@ static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw)
 
 	switch (hw->mac.type) {
 	case e1000_82573:
+	case e1000_82574:
 		if (((eecd >> 15) & 0x3) == 0x3) {
 			nvm->type = e1000_nvm_flash_hw;
 			nvm->word_size = 2048;
@@ -245,6 +258,17 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
 		break;
 	}
 
+	switch (hw->mac.type) {
+	case e1000_82574:
+		func->check_mng_mode = e1000_check_mng_mode_82574;
+		func->led_on = e1000_led_on_82574;
+		break;
+	default:
+		func->check_mng_mode = e1000e_check_mng_mode_generic;
+		func->led_on = e1000e_led_on_generic;
+		break;
+	}
+
 	return 0;
 }
 
@@ -330,6 +354,8 @@ static s32 e1000_get_variants_82571(struct e1000_adapter *adapter)
 static s32 e1000_get_phy_id_82571(struct e1000_hw *hw)
 {
 	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_id = 0;
 
 	switch (hw->mac.type) {
 	case e1000_82571:
@@ -345,6 +371,20 @@ static s32 e1000_get_phy_id_82571(struct e1000_hw *hw)
 	case e1000_82573:
 		return e1000e_get_phy_id(hw);
 		break;
+	case e1000_82574:
+		ret_val = e1e_rphy(hw, PHY_ID1, &phy_id);
+		if (ret_val)
+			return ret_val;
+
+		phy->id = (u32)(phy_id << 16);
+		udelay(20);
+		ret_val = e1e_rphy(hw, PHY_ID2, &phy_id);
+		if (ret_val)
+			return ret_val;
+
+		phy->id |= (u32)(phy_id);
+		phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
+		break;
 	default:
 		return -E1000_ERR_PHY;
 		break;
@@ -421,7 +461,7 @@ static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw)
 	if (ret_val)
 		return ret_val;
 
-	if (hw->mac.type != e1000_82573)
+	if (hw->mac.type != e1000_82573 && hw->mac.type != e1000_82574)
 		ret_val = e1000e_acquire_nvm(hw);
 
 	if (ret_val)
@@ -461,6 +501,7 @@ static s32 e1000_write_nvm_82571(struct e1000_hw *hw, u16 offset, u16 words,
 
 	switch (hw->mac.type) {
 	case e1000_82573:
+	case e1000_82574:
 		ret_val = e1000_write_nvm_eewr_82571(hw, offset, words, data);
 		break;
 	case e1000_82571:
@@ -735,7 +776,7 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
 	 * Must acquire the MDIO ownership before MAC reset.
 	 * Ownership defaults to firmware after a reset.
 	 */
-	if (hw->mac.type == e1000_82573) {
+	if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
 		extcnf_ctrl = er32(EXTCNF_CTRL);
 		extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
 
@@ -776,7 +817,7 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
 	 * Need to wait for Phy configuration completion before accessing
 	 * NVM and Phy.
 	 */
-	if (hw->mac.type == e1000_82573)
+	if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574)
 		msleep(25);
 
 	/* Clear any pending interrupt events. */
@@ -843,7 +884,7 @@ static s32 e1000_init_hw_82571(struct e1000_hw *hw)
 	ew32(TXDCTL(0), reg_data);
 
 	/* ...for both queues. */
-	if (mac->type != e1000_82573) {
+	if (mac->type != e1000_82573 && mac->type != e1000_82574) {
 		reg_data = er32(TXDCTL(1));
 		reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
 			   E1000_TXDCTL_FULL_TX_DESC_WB |
@@ -918,19 +959,28 @@ static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw)
 	}
 
 	/* Device Control */
-	if (hw->mac.type == e1000_82573) {
+	if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
 		reg = er32(CTRL);
 		reg &= ~(1 << 29);
 		ew32(CTRL, reg);
 	}
 
 	/* Extended Device Control */
-	if (hw->mac.type == e1000_82573) {
+	if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
 		reg = er32(CTRL_EXT);
 		reg &= ~(1 << 23);
 		reg |= (1 << 22);
 		ew32(CTRL_EXT, reg);
 	}
+
+	/* PCI-Ex Control Register */
+	if (hw->mac.type == e1000_82574) {
+		reg = er32(GCR);
+		reg |= (1 << 22);
+		ew32(GCR, reg);
+	}
+
+	return;
 }
 
 /**
@@ -947,7 +997,7 @@ void e1000e_clear_vfta(struct e1000_hw *hw)
 	u32 vfta_offset = 0;
 	u32 vfta_bit_in_reg = 0;
 
-	if (hw->mac.type == e1000_82573) {
+	if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
 		if (hw->mng_cookie.vlan_id != 0) {
 			/*
 			 * The VFTA is a 4096b bit-field, each identifying
@@ -976,6 +1026,48 @@ void e1000e_clear_vfta(struct e1000_hw *hw)
 }
 
 /**
+ *  e1000_check_mng_mode_82574 - Check manageability is enabled
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the NVM Initialization Control Word 2 and returns true
+ *  (>0) if any manageability is enabled, else false (0).
+ **/
+static bool e1000_check_mng_mode_82574(struct e1000_hw *hw)
+{
+	u16 data;
+
+	e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &data);
+	return (data & E1000_NVM_INIT_CTRL2_MNGM) != 0;
+}
+
+/**
+ *  e1000_led_on_82574 - Turn LED on
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn LED on.
+ **/
+static s32 e1000_led_on_82574(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	u32 i;
+
+	ctrl = hw->mac.ledctl_mode2;
+	if (!(E1000_STATUS_LU & er32(STATUS))) {
+		/*
+		 * If no link, then turn LED on by setting the invert bit
+		 * for each LED that's "on" (0x0E) in ledctl_mode2.
+		 */
+		for (i = 0; i < 4; i++)
+			if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
+			    E1000_LEDCTL_MODE_LED_ON)
+				ctrl |= (E1000_LEDCTL_LED0_IVRT << (i * 8));
+	}
+	ew32(LEDCTL, ctrl);
+
+	return 0;
+}
+
+/**
  *  e1000_update_mc_addr_list_82571 - Update Multicast addresses
  *  @hw: pointer to the HW structure
  *  @mc_addr_list: array of multicast addresses to program
@@ -1018,7 +1110,8 @@ static s32 e1000_setup_link_82571(struct e1000_hw *hw)
 	 * the default flow control setting, so we explicitly
 	 * set it to full.
 	 */
-	if (hw->mac.type == e1000_82573)
+	if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) &&
+	    hw->fc.type == e1000_fc_default)
 		hw->fc.type = e1000_fc_full;
 
 	return e1000e_setup_link(hw);
@@ -1045,6 +1138,7 @@ static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw)
 
 	switch (hw->phy.type) {
 	case e1000_phy_m88:
+	case e1000_phy_bm:
 		ret_val = e1000e_copper_link_setup_m88(hw);
 		break;
 	case e1000_phy_igp_2:
@@ -1114,11 +1208,10 @@ static s32 e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data)
 		return ret_val;
 	}
 
-	if (hw->mac.type == e1000_82573 &&
+	if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) &&
 	    *data == ID_LED_RESERVED_F746)
 		*data = ID_LED_DEFAULT_82573;
-	else if (*data == ID_LED_RESERVED_0000 ||
-		 *data == ID_LED_RESERVED_FFFF)
+	else if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
 		*data = ID_LED_DEFAULT;
 
 	return 0;
@@ -1265,13 +1358,13 @@ static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw)
 }
 
 static struct e1000_mac_operations e82571_mac_ops = {
-	.mng_mode_enab		= E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
+	/* .check_mng_mode: mac type dependent */
 	/* .check_for_link: media type dependent */
 	.cleanup_led		= e1000e_cleanup_led_generic,
 	.clear_hw_cntrs		= e1000_clear_hw_cntrs_82571,
 	.get_bus_info		= e1000e_get_bus_info_pcie,
 	/* .get_link_up_info: media type dependent */
-	.led_on			= e1000e_led_on_generic,
+	/* .led_on: mac type dependent */
 	.led_off		= e1000e_led_off_generic,
 	.update_mc_addr_list	= e1000_update_mc_addr_list_82571,
 	.reset_hw		= e1000_reset_hw_82571,
@@ -1312,6 +1405,22 @@ static struct e1000_phy_operations e82_phy_ops_m88 = {
 	.write_phy_reg		= e1000e_write_phy_reg_m88,
 };
 
+static struct e1000_phy_operations e82_phy_ops_bm = {
+	.acquire_phy		= e1000_get_hw_semaphore_82571,
+	.check_reset_block	= e1000e_check_reset_block_generic,
+	.commit_phy		= e1000e_phy_sw_reset,
+	.force_speed_duplex	= e1000e_phy_force_speed_duplex_m88,
+	.get_cfg_done		= e1000e_get_cfg_done,
+	.get_cable_length	= e1000e_get_cable_length_m88,
+	.get_phy_info		= e1000e_get_phy_info_m88,
+	.read_phy_reg		= e1000e_read_phy_reg_bm2,
+	.release_phy		= e1000_put_hw_semaphore_82571,
+	.reset_phy		= e1000e_phy_hw_reset_generic,
+	.set_d0_lplu_state	= e1000_set_d0_lplu_state_82571,
+	.set_d3_lplu_state	= e1000e_set_d3_lplu_state,
+	.write_phy_reg		= e1000e_write_phy_reg_bm2,
+};
+
 static struct e1000_nvm_operations e82571_nvm_ops = {
 	.acquire_nvm		= e1000_acquire_nvm_82571,
 	.read_nvm		= e1000e_read_nvm_eerd,
@@ -1375,3 +1484,21 @@ struct e1000_info e1000_82573_info = {
 	.nvm_ops		= &e82571_nvm_ops,
 };
 
+struct e1000_info e1000_82574_info = {
+	.mac			= e1000_82574,
+	.flags			= FLAG_HAS_HW_VLAN_FILTER
+				  | FLAG_HAS_MSIX
+				  | FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_HAS_WOL
+				  | FLAG_APME_IN_CTRL3
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_SMART_POWER_DOWN
+				  | FLAG_HAS_AMT
+				  | FLAG_HAS_CTRLEXT_ON_LOAD,
+	.pba			= 20,
+	.get_variants		= e1000_get_variants_82571,
+	.mac_ops		= &e82571_mac_ops,
+	.phy_ops		= &e82_phy_ops_bm,
+	.nvm_ops		= &e82571_nvm_ops,
+};
+
diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h
index 4b21fa9..48f79ec 100644
--- a/drivers/net/e1000e/defines.h
+++ b/drivers/net/e1000e/defines.h
@@ -71,9 +71,11 @@
 #define E1000_CTRL_EXT_RO_DIS    0x00020000 /* Relaxed Ordering disable */
 #define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
 #define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES  0x00C00000
+#define E1000_CTRL_EXT_EIAME          0x01000000
 #define E1000_CTRL_EXT_DRV_LOAD       0x10000000 /* Driver loaded bit for FW */
 #define E1000_CTRL_EXT_IAME           0x08000000 /* Interrupt acknowledge Auto-mask */
 #define E1000_CTRL_EXT_INT_TIMER_CLR  0x20000000 /* Clear Interrupt timers after IMS clear */
+#define E1000_CTRL_EXT_PBA_CLR        0x80000000 /* PBA Clear */
 
 /* Receive Descriptor bit definitions */
 #define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
@@ -299,6 +301,7 @@
 #define E1000_RXCSUM_IPPCSE    0x00001000   /* IP payload checksum enable */
 
 /* Header split receive */
+#define E1000_RFCTL_ACK_DIS             0x00001000
 #define E1000_RFCTL_EXTEN               0x00008000
 #define E1000_RFCTL_IPV6_EX_DIS         0x00010000
 #define E1000_RFCTL_NEW_IPV6_EXT_DIS    0x00020000
@@ -363,6 +366,11 @@
 #define E1000_ICR_RXDMT0        0x00000010 /* Rx desc min. threshold (0) */
 #define E1000_ICR_RXT0          0x00000080 /* Rx timer intr (ring 0) */
 #define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver should claim the interrupt */
+#define E1000_ICR_RXQ0          0x00100000 /* Rx Queue 0 Interrupt */
+#define E1000_ICR_RXQ1          0x00200000 /* Rx Queue 1 Interrupt */
+#define E1000_ICR_TXQ0          0x00400000 /* Tx Queue 0 Interrupt */
+#define E1000_ICR_TXQ1          0x00800000 /* Tx Queue 1 Interrupt */
+#define E1000_ICR_OTHER         0x01000000 /* Other Interrupts */
 
 /*
  * This defines the bits that are set in the Interrupt Mask
@@ -386,6 +394,11 @@
 #define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* Rx sequence error */
 #define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* Rx desc min. threshold */
 #define E1000_IMS_RXT0      E1000_ICR_RXT0      /* Rx timer intr */
+#define E1000_IMS_RXQ0      E1000_ICR_RXQ0      /* Rx Queue 0 Interrupt */
+#define E1000_IMS_RXQ1      E1000_ICR_RXQ1      /* Rx Queue 1 Interrupt */
+#define E1000_IMS_TXQ0      E1000_ICR_TXQ0      /* Tx Queue 0 Interrupt */
+#define E1000_IMS_TXQ1      E1000_ICR_TXQ1      /* Tx Queue 1 Interrupt */
+#define E1000_IMS_OTHER     E1000_ICR_OTHER     /* Other Interrupts */
 
 /* Interrupt Cause Set */
 #define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
index ef66dc4..0a1916b 100644
--- a/drivers/net/e1000e/e1000.h
+++ b/drivers/net/e1000e/e1000.h
@@ -62,6 +62,11 @@ struct e1000_info;
 	e_printk(KERN_NOTICE, adapter, format, ## arg)
 
 
+/* Interrupt modes, as used by the IntMode paramter */
+#define E1000E_INT_MODE_LEGACY		0
+#define E1000E_INT_MODE_MSI		1
+#define E1000E_INT_MODE_MSIX		2
+
 /* Tx/Rx descriptor defines */
 #define E1000_DEFAULT_TXD		256
 #define E1000_MAX_TXD			4096
@@ -95,6 +100,7 @@ enum e1000_boards {
 	board_82571,
 	board_82572,
 	board_82573,
+	board_82574,
 	board_80003es2lan,
 	board_ich8lan,
 	board_ich9lan,
@@ -147,6 +153,12 @@ struct e1000_ring {
 	/* array of buffer information structs */
 	struct e1000_buffer *buffer_info;
 
+	char name[IFNAMSIZ + 5];
+	u32 ims_val;
+	u32 itr_val;
+	u16 itr_register;
+	int set_itr;
+
 	struct sk_buff *rx_skb_top;
 
 	struct e1000_queue_stats stats;
@@ -275,6 +287,9 @@ struct e1000_adapter {
 	u32 test_icr;
 
 	u32 msg_enable;
+	struct msix_entry *msix_entries;
+	int int_mode;
+	u32 eiac_mask;
 
 	u32 eeprom_wol;
 	u32 wol;
@@ -307,6 +322,7 @@ struct e1000_info {
 #define FLAG_HAS_SWSM_ON_LOAD             (1 << 6)
 #define FLAG_HAS_JUMBO_FRAMES             (1 << 7)
 #define FLAG_IS_ICH                       (1 << 9)
+#define FLAG_HAS_MSIX                     (1 << 10)
 #define FLAG_HAS_SMART_POWER_DOWN         (1 << 11)
 #define FLAG_IS_QUAD_PORT_A               (1 << 12)
 #define FLAG_IS_QUAD_PORT                 (1 << 13)
@@ -365,6 +381,8 @@ extern int e1000e_setup_tx_resources(struct e1000_adapter *adapter);
 extern void e1000e_free_rx_resources(struct e1000_adapter *adapter);
 extern void e1000e_free_tx_resources(struct e1000_adapter *adapter);
 extern void e1000e_update_stats(struct e1000_adapter *adapter);
+extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter);
+extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter);
 
 extern unsigned int copybreak;
 
@@ -373,6 +391,7 @@ extern char *e1000e_get_hw_dev_name(struct e1000_hw *hw);
 extern struct e1000_info e1000_82571_info;
 extern struct e1000_info e1000_82572_info;
 extern struct e1000_info e1000_82573_info;
+extern struct e1000_info e1000_82574_info;
 extern struct e1000_info e1000_ich8_info;
 extern struct e1000_info e1000_ich9_info;
 extern struct e1000_info e1000_ich10_info;
@@ -453,6 +472,8 @@ extern enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id);
 extern s32 e1000e_determine_phy_address(struct e1000_hw *hw);
 extern s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data);
 extern s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data);
+extern s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data);
+extern s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data);
 extern void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl);
 extern s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data);
 extern s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
@@ -523,7 +544,12 @@ static inline s32 e1000_get_phy_info(struct e1000_hw *hw)
 	return hw->phy.ops.get_phy_info(hw);
 }
 
-extern bool e1000e_check_mng_mode(struct e1000_hw *hw);
+static inline s32 e1000e_check_mng_mode(struct e1000_hw *hw)
+{
+	return hw->mac.ops.check_mng_mode(hw);
+}
+
+extern bool e1000e_check_mng_mode_generic(struct e1000_hw *hw);
 extern bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw);
 extern s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length);
 
diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c
index dc552d7..da9c09c 100644
--- a/drivers/net/e1000e/es2lan.c
+++ b/drivers/net/e1000e/es2lan.c
@@ -1247,7 +1247,7 @@ static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw)
 }
 
 static struct e1000_mac_operations es2_mac_ops = {
-	.mng_mode_enab		= E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
+	.check_mng_mode		= e1000e_check_mng_mode_generic,
 	/* check_for_link dependent on media type */
 	.cleanup_led		= e1000e_cleanup_led_generic,
 	.clear_hw_cntrs		= e1000_clear_hw_cntrs_80003es2lan,
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index a89498d..52b762e 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -568,6 +568,7 @@ static int e1000_set_eeprom(struct net_device *netdev,
 	 * and flush shadow RAM for 82573 controllers
 	 */
 	if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG) ||
+			       (hw->mac.type == e1000_82574) ||
 			       (hw->mac.type == e1000_82573)))
 		e1000e_update_nvm_checksum(hw);
 
@@ -779,6 +780,7 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
 		toggle = 0x7FFFF3FF;
 		break;
 	case e1000_82573:
+	case e1000_82574:
 	case e1000_ich8lan:
 	case e1000_ich9lan:
 	case e1000_ich10lan:
@@ -887,10 +889,18 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
 	u32 shared_int = 1;
 	u32 irq = adapter->pdev->irq;
 	int i;
+	int ret_val = 0;
+	int int_mode = E1000E_INT_MODE_LEGACY;
 
 	*data = 0;
 
-	/* NOTE: we don't test MSI interrupts here, yet */
+	/* NOTE: we don't test MSI/MSI-X interrupts here, yet */
+	if (adapter->int_mode == E1000E_INT_MODE_MSIX) {
+		int_mode = adapter->int_mode;
+		e1000e_reset_interrupt_capability(adapter);
+		adapter->int_mode = E1000E_INT_MODE_LEGACY;
+		e1000e_set_interrupt_capability(adapter);
+	}
 	/* Hook up test interrupt handler just for this test */
 	if (!request_irq(irq, &e1000_test_intr, IRQF_PROBE_SHARED, netdev->name,
 			 netdev)) {
@@ -898,7 +908,8 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
 	} else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED,
 		 netdev->name, netdev)) {
 		*data = 1;
-		return -1;
+		ret_val = -1;
+		goto out;
 	}
 	e_info("testing %s interrupt\n", (shared_int ? "shared" : "unshared"));
 
@@ -988,7 +999,14 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
 	/* Unhook test interrupt handler */
 	free_irq(irq, netdev);
 
-	return *data;
+out:
+	if (int_mode == E1000E_INT_MODE_MSIX) {
+		e1000e_reset_interrupt_capability(adapter);
+		adapter->int_mode = int_mode;
+		e1000e_set_interrupt_capability(adapter);
+	}
+
+	return ret_val;
 }
 
 static void e1000_free_desc_rings(struct e1000_adapter *adapter)
@@ -1769,11 +1787,13 @@ static void e1000_led_blink_callback(unsigned long data)
 static int e1000_phys_id(struct net_device *netdev, u32 data)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
 
 	if (!data)
 		data = INT_MAX;
 
-	if (adapter->hw.phy.type == e1000_phy_ife) {
+	if ((hw->phy.type == e1000_phy_ife) ||
+	    (hw->mac.type == e1000_82574)) {
 		if (!adapter->blink_timer.function) {
 			init_timer(&adapter->blink_timer);
 			adapter->blink_timer.function =
@@ -1783,16 +1803,16 @@ static int e1000_phys_id(struct net_device *netdev, u32 data)
 		mod_timer(&adapter->blink_timer, jiffies);
 		msleep_interruptible(data * 1000);
 		del_timer_sync(&adapter->blink_timer);
-		e1e_wphy(&adapter->hw,
-				    IFE_PHY_SPECIAL_CONTROL_LED, 0);
+		if (hw->phy.type == e1000_phy_ife)
+			e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0);
 	} else {
-		e1000e_blink_led(&adapter->hw);
+		e1000e_blink_led(hw);
 		msleep_interruptible(data * 1000);
 	}
 
-	adapter->hw.mac.ops.led_off(&adapter->hw);
+	hw->mac.ops.led_off(hw);
 	clear_bit(E1000_LED_ON, &adapter->led_status);
-	adapter->hw.mac.ops.cleanup_led(&adapter->hw);
+	hw->mac.ops.cleanup_led(hw);
 
 	return 0;
 }
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h
index 5d2acc5..f66ed37 100644
--- a/drivers/net/e1000e/hw.h
+++ b/drivers/net/e1000e/hw.h
@@ -65,7 +65,11 @@ enum e1e_registers {
 	E1000_ICS      = 0x000C8, /* Interrupt Cause Set - WO */
 	E1000_IMS      = 0x000D0, /* Interrupt Mask Set - RW */
 	E1000_IMC      = 0x000D8, /* Interrupt Mask Clear - WO */
+	E1000_EIAC_82574 = 0x000DC, /* Ext. Interrupt Auto Clear - RW */
 	E1000_IAM      = 0x000E0, /* Interrupt Acknowledge Auto Mask */
+	E1000_IVAR     = 0x000E4, /* Interrupt Vector Allocation - RW */
+	E1000_EITR_82574_BASE = 0x000E8, /* Interrupt Throttling - RW */
+#define E1000_EITR_82574(_n) (E1000_EITR_82574_BASE + (_n << 2))
 	E1000_RCTL     = 0x00100, /* Rx Control - RW */
 	E1000_FCTTV    = 0x00170, /* Flow Control Transmit Timer Value - RW */
 	E1000_TXCW     = 0x00178, /* Tx Configuration Word - RW */
@@ -332,6 +336,7 @@ enum e1e_registers {
 #define E1000_DEV_ID_82573E			0x108B
 #define E1000_DEV_ID_82573E_IAMT		0x108C
 #define E1000_DEV_ID_82573L			0x109A
+#define E1000_DEV_ID_82574L			0x10D3
 
 #define E1000_DEV_ID_80003ES2LAN_COPPER_DPT	0x1096
 #define E1000_DEV_ID_80003ES2LAN_SERDES_DPT	0x1098
@@ -360,12 +365,15 @@ enum e1e_registers {
 #define E1000_DEV_ID_ICH10_D_BM_LM		0x10DE
 #define E1000_DEV_ID_ICH10_D_BM_LF		0x10DF
 
+#define E1000_REVISION_4 4
+
 #define E1000_FUNC_1 1
 
 enum e1000_mac_type {
 	e1000_82571,
 	e1000_82572,
 	e1000_82573,
+	e1000_82574,
 	e1000_80003es2lan,
 	e1000_ich8lan,
 	e1000_ich9lan,
@@ -700,8 +708,7 @@ struct e1000_host_mng_command_info {
 
 /* Function pointers and static data for the MAC. */
 struct e1000_mac_operations {
-	u32			mng_mode_enab;
-
+	bool (*check_mng_mode)(struct e1000_hw *);
 	s32  (*check_for_link)(struct e1000_hw *);
 	s32  (*cleanup_led)(struct e1000_hw *);
 	void (*clear_hw_cntrs)(struct e1000_hw *);
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
index 0e76bb0..019b9c0 100644
--- a/drivers/net/e1000e/ich8lan.c
+++ b/drivers/net/e1000e/ich8lan.c
@@ -422,6 +422,22 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
 }
 
 /**
+ *  e1000_check_mng_mode_ich8lan - Checks management mode
+ *  @hw: pointer to the HW structure
+ *
+ *  This checks if the adapter has manageability enabled.
+ *  This is a function pointer entry point only called by read/write
+ *  routines for the PHY and NVM parts.
+ **/
+static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw)
+{
+	u32 fwsm = er32(FWSM);
+
+	return (fwsm & E1000_FWSM_MODE_MASK) ==
+		(E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
+}
+
+/**
  *  e1000_check_reset_block_ich8lan - Check if PHY reset is blocked
  *  @hw: pointer to the HW structure
  *
@@ -2400,7 +2416,7 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
 }
 
 static struct e1000_mac_operations ich8_mac_ops = {
-	.mng_mode_enab		= E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
+	.check_mng_mode		= e1000_check_mng_mode_ich8lan,
 	.check_for_link		= e1000e_check_for_copper_link,
 	.cleanup_led		= e1000_cleanup_led_ich8lan,
 	.clear_hw_cntrs		= e1000_clear_hw_cntrs_ich8lan,
diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c
index f1f4e9d..c733730 100644
--- a/drivers/net/e1000e/lib.c
+++ b/drivers/net/e1000e/lib.c
@@ -2222,17 +2222,18 @@ static s32 e1000_mng_enable_host_if(struct e1000_hw *hw)
 }
 
 /**
- *  e1000e_check_mng_mode - check management mode
+ *  e1000e_check_mng_mode_generic - check management mode
  *  @hw: pointer to the HW structure
  *
  *  Reads the firmware semaphore register and returns true (>0) if
  *  manageability is enabled, else false (0).
  **/
-bool e1000e_check_mng_mode(struct e1000_hw *hw)
+bool e1000e_check_mng_mode_generic(struct e1000_hw *hw)
 {
 	u32 fwsm = er32(FWSM);
 
-	return (fwsm & E1000_FWSM_MODE_MASK) == hw->mac.ops.mng_mode_enab;
+	return (fwsm & E1000_FWSM_MODE_MASK) ==
+		(E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
 }
 
 /**
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 2d9bcb0..0925204 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -55,6 +55,7 @@ static const struct e1000_info *e1000_info_tbl[] = {
 	[board_82571]		= &e1000_82571_info,
 	[board_82572]		= &e1000_82572_info,
 	[board_82573]		= &e1000_82573_info,
+	[board_82574]		= &e1000_82574_info,
 	[board_80003es2lan]	= &e1000_es2_info,
 	[board_ich8lan]		= &e1000_ich8_info,
 	[board_ich9lan]		= &e1000_ich9_info,
@@ -1180,8 +1181,8 @@ static irqreturn_t e1000_intr(int irq, void *data)
 	struct net_device *netdev = data;
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
-
 	u32 rctl, icr = er32(ICR);
+
 	if (!icr)
 		return IRQ_NONE;  /* Not our interrupt */
 
@@ -1237,6 +1238,263 @@ static irqreturn_t e1000_intr(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t e1000_msix_other(int irq, void *data)
+{
+	struct net_device *netdev = data;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u32 icr = er32(ICR);
+
+	if (!(icr & E1000_ICR_INT_ASSERTED)) {
+		ew32(IMS, E1000_IMS_OTHER);
+		return IRQ_NONE;
+	}
+
+	if (icr & adapter->eiac_mask)
+		ew32(ICS, (icr & adapter->eiac_mask));
+
+	if (icr & E1000_ICR_OTHER) {
+		if (!(icr & E1000_ICR_LSC))
+			goto no_link_interrupt;
+		hw->mac.get_link_status = 1;
+		/* guard against interrupt when we're going down */
+		if (!test_bit(__E1000_DOWN, &adapter->state))
+			mod_timer(&adapter->watchdog_timer, jiffies + 1);
+	}
+
+no_link_interrupt:
+	ew32(IMS, E1000_IMS_LSC | E1000_IMS_OTHER);
+
+	return IRQ_HANDLED;
+}
+
+
+static irqreturn_t e1000_intr_msix_tx(int irq, void *data)
+{
+	struct net_device *netdev = data;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+
+
+	adapter->total_tx_bytes = 0;
+	adapter->total_tx_packets = 0;
+
+	if (!e1000_clean_tx_irq(adapter))
+		/* Ring was not completely cleaned, so fire another interrupt */
+		ew32(ICS, tx_ring->ims_val);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t e1000_intr_msix_rx(int irq, void *data)
+{
+	struct net_device *netdev = data;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
+	/* Write the ITR value calculated at the end of the
+	 * previous interrupt.
+	 */
+	if (adapter->rx_ring->set_itr) {
+		writel(1000000000 / (adapter->rx_ring->itr_val * 256),
+		       adapter->hw.hw_addr + adapter->rx_ring->itr_register);
+		adapter->rx_ring->set_itr = 0;
+	}
+
+	if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
+		adapter->total_rx_bytes = 0;
+		adapter->total_rx_packets = 0;
+		__netif_rx_schedule(netdev, &adapter->napi);
+	}
+	return IRQ_HANDLED;
+}
+
+/**
+ * e1000_configure_msix - Configure MSI-X hardware
+ *
+ * e1000_configure_msix sets up the hardware to properly
+ * generate MSI-X interrupts.
+ **/
+static void e1000_configure_msix(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct e1000_ring *rx_ring = adapter->rx_ring;
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+	int vector = 0;
+	u32 ctrl_ext, ivar = 0;
+
+	adapter->eiac_mask = 0;
+
+	/* Workaround issue with spurious interrupts on 82574 in MSI-X mode */
+	if (hw->mac.type == e1000_82574) {
+		u32 rfctl = er32(RFCTL);
+		rfctl |= E1000_RFCTL_ACK_DIS;
+		ew32(RFCTL, rfctl);
+	}
+
+#define E1000_IVAR_INT_ALLOC_VALID	0x8
+	/* Configure Rx vector */
+	rx_ring->ims_val = E1000_IMS_RXQ0;
+	adapter->eiac_mask |= rx_ring->ims_val;
+	if (rx_ring->itr_val)
+		writel(1000000000 / (rx_ring->itr_val * 256),
+		       hw->hw_addr + rx_ring->itr_register);
+	else
+		writel(1, hw->hw_addr + rx_ring->itr_register);
+	ivar = E1000_IVAR_INT_ALLOC_VALID | vector;
+
+	/* Configure Tx vector */
+	tx_ring->ims_val = E1000_IMS_TXQ0;
+	vector++;
+	if (tx_ring->itr_val)
+		writel(1000000000 / (tx_ring->itr_val * 256),
+		       hw->hw_addr + tx_ring->itr_register);
+	else
+		writel(1, hw->hw_addr + tx_ring->itr_register);
+	adapter->eiac_mask |= tx_ring->ims_val;
+	ivar |= ((E1000_IVAR_INT_ALLOC_VALID | vector) << 8);
+
+	/* set vector for Other Causes, e.g. link changes */
+	vector++;
+	ivar |= ((E1000_IVAR_INT_ALLOC_VALID | vector) << 16);
+	if (rx_ring->itr_val)
+		writel(1000000000 / (rx_ring->itr_val * 256),
+		       hw->hw_addr + E1000_EITR_82574(vector));
+	else
+		writel(1, hw->hw_addr + E1000_EITR_82574(vector));
+
+	/* Cause Tx interrupts on every write back */
+	ivar |= (1 << 31);
+
+	ew32(IVAR, ivar);
+
+	/* enable MSI-X PBA support */
+	ctrl_ext = er32(CTRL_EXT);
+	ctrl_ext |= E1000_CTRL_EXT_PBA_CLR;
+
+	/* Auto-Mask Other interrupts upon ICR read */
+#define E1000_EIAC_MASK_82574   0x01F00000
+	ew32(IAM, ~E1000_EIAC_MASK_82574 | E1000_IMS_OTHER);
+	ctrl_ext |= E1000_CTRL_EXT_EIAME;
+	ew32(CTRL_EXT, ctrl_ext);
+	e1e_flush();
+}
+
+void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter)
+{
+	if (adapter->msix_entries) {
+		pci_disable_msix(adapter->pdev);
+		kfree(adapter->msix_entries);
+		adapter->msix_entries = NULL;
+	} else if (adapter->flags & FLAG_MSI_ENABLED) {
+		pci_disable_msi(adapter->pdev);
+		adapter->flags &= ~FLAG_MSI_ENABLED;
+	}
+
+	return;
+}
+
+/**
+ * e1000e_set_interrupt_capability - set MSI or MSI-X if supported
+ *
+ * Attempt to configure interrupts using the best available
+ * capabilities of the hardware and kernel.
+ **/
+void e1000e_set_interrupt_capability(struct e1000_adapter *adapter)
+{
+	int err;
+	int numvecs, i;
+
+
+	switch (adapter->int_mode) {
+	case E1000E_INT_MODE_MSIX:
+		if (adapter->flags & FLAG_HAS_MSIX) {
+			numvecs = 3; /* RxQ0, TxQ0 and other */
+			adapter->msix_entries = kcalloc(numvecs,
+						      sizeof(struct msix_entry),
+						      GFP_KERNEL);
+			if (adapter->msix_entries) {
+				for (i = 0; i < numvecs; i++)
+					adapter->msix_entries[i].entry = i;
+
+				err = pci_enable_msix(adapter->pdev,
+						      adapter->msix_entries,
+						      numvecs);
+				if (err == 0)
+					return;
+			}
+			/* MSI-X failed, so fall through and try MSI */
+			e_err("Failed to initialize MSI-X interrupts.  "
+			      "Falling back to MSI interrupts.\n");
+			e1000e_reset_interrupt_capability(adapter);
+		}
+		adapter->int_mode = E1000E_INT_MODE_MSI;
+		/* Fall through */
+	case E1000E_INT_MODE_MSI:
+		if (!pci_enable_msi(adapter->pdev)) {
+			adapter->flags |= FLAG_MSI_ENABLED;
+		} else {
+			adapter->int_mode = E1000E_INT_MODE_LEGACY;
+			e_err("Failed to initialize MSI interrupts.  Falling "
+			      "back to legacy interrupts.\n");
+		}
+		/* Fall through */
+	case E1000E_INT_MODE_LEGACY:
+		/* Don't do anything; this is the system default */
+		break;
+	}
+
+	return;
+}
+
+/**
+ * e1000_request_msix - Initialize MSI-X interrupts
+ *
+ * e1000_request_msix allocates MSI-X vectors and requests interrupts from the
+ * kernel.
+ **/
+static int e1000_request_msix(struct e1000_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	int err = 0, vector = 0;
+
+	if (strlen(netdev->name) < (IFNAMSIZ - 5))
+		sprintf(adapter->rx_ring->name, "%s-rx0", netdev->name);
+	else
+		memcpy(adapter->rx_ring->name, netdev->name, IFNAMSIZ);
+	err = request_irq(adapter->msix_entries[vector].vector,
+			  &e1000_intr_msix_rx, 0, adapter->rx_ring->name,
+			  netdev);
+	if (err)
+		goto out;
+	adapter->rx_ring->itr_register = E1000_EITR_82574(vector);
+	adapter->rx_ring->itr_val = adapter->itr;
+	vector++;
+
+	if (strlen(netdev->name) < (IFNAMSIZ - 5))
+		sprintf(adapter->tx_ring->name, "%s-tx0", netdev->name);
+	else
+		memcpy(adapter->tx_ring->name, netdev->name, IFNAMSIZ);
+	err = request_irq(adapter->msix_entries[vector].vector,
+			  &e1000_intr_msix_tx, 0, adapter->tx_ring->name,
+			  netdev);
+	if (err)
+		goto out;
+	adapter->tx_ring->itr_register = E1000_EITR_82574(vector);
+	adapter->tx_ring->itr_val = adapter->itr;
+	vector++;
+
+	err = request_irq(adapter->msix_entries[vector].vector,
+			  &e1000_msix_other, 0, netdev->name, netdev);
+	if (err)
+		goto out;
+
+	e1000_configure_msix(adapter);
+	return 0;
+out:
+	return err;
+}
+
 /**
  * e1000_request_irq - initialize interrupts
  *
@@ -1246,29 +1504,33 @@ static irqreturn_t e1000_intr(int irq, void *data)
 static int e1000_request_irq(struct e1000_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
-	int irq_flags = IRQF_SHARED;
 	int err;
 
-	if (!(adapter->flags & FLAG_MSI_TEST_FAILED)) {
-		err = pci_enable_msi(adapter->pdev);
-		if (!err) {
-			adapter->flags |= FLAG_MSI_ENABLED;
-			irq_flags = 0;
-		}
+	if (adapter->msix_entries) {
+		err = e1000_request_msix(adapter);
+		if (!err)
+			return err;
+		/* fall back to MSI */
+		e1000e_reset_interrupt_capability(adapter);
+		adapter->int_mode = E1000E_INT_MODE_MSI;
+		e1000e_set_interrupt_capability(adapter);
 	}
+	if (adapter->flags & FLAG_MSI_ENABLED) {
+		err = request_irq(adapter->pdev->irq, &e1000_intr_msi, 0,
+				  netdev->name, netdev);
+		if (!err)
+			return err;
 
-	err = request_irq(adapter->pdev->irq,
-			  ((adapter->flags & FLAG_MSI_ENABLED) ?
-				&e1000_intr_msi : &e1000_intr),
-			  irq_flags, netdev->name, netdev);
-	if (err) {
-		if (adapter->flags & FLAG_MSI_ENABLED) {
-			pci_disable_msi(adapter->pdev);
-			adapter->flags &= ~FLAG_MSI_ENABLED;
-		}
-		e_err("Unable to allocate interrupt, Error: %d\n", err);
+		/* fall back to legacy interrupt */
+		e1000e_reset_interrupt_capability(adapter);
+		adapter->int_mode = E1000E_INT_MODE_LEGACY;
 	}
 
+	err = request_irq(adapter->pdev->irq, &e1000_intr, IRQF_SHARED,
+			  netdev->name, netdev);
+	if (err)
+		e_err("Unable to allocate interrupt, Error: %d\n", err);
+
 	return err;
 }
 
@@ -1276,11 +1538,21 @@ static void e1000_free_irq(struct e1000_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
 
-	free_irq(adapter->pdev->irq, netdev);
-	if (adapter->flags & FLAG_MSI_ENABLED) {
-		pci_disable_msi(adapter->pdev);
-		adapter->flags &= ~FLAG_MSI_ENABLED;
+	if (adapter->msix_entries) {
+		int vector = 0;
+
+		free_irq(adapter->msix_entries[vector].vector, netdev);
+		vector++;
+
+		free_irq(adapter->msix_entries[vector].vector, netdev);
+		vector++;
+
+		/* Other Causes interrupt vector */
+		free_irq(adapter->msix_entries[vector].vector, netdev);
+		return;
 	}
+
+	free_irq(adapter->pdev->irq, netdev);
 }
 
 /**
@@ -1291,6 +1563,8 @@ static void e1000_irq_disable(struct e1000_adapter *adapter)
 	struct e1000_hw *hw = &adapter->hw;
 
 	ew32(IMC, ~0);
+	if (adapter->msix_entries)
+		ew32(EIAC_82574, 0);
 	e1e_flush();
 	synchronize_irq(adapter->pdev->irq);
 }
@@ -1302,7 +1576,12 @@ static void e1000_irq_enable(struct e1000_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
 
-	ew32(IMS, IMS_ENABLE_MASK);
+	if (adapter->msix_entries) {
+		ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574);
+		ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER | E1000_IMS_LSC);
+	} else {
+		ew32(IMS, IMS_ENABLE_MASK);
+	}
 	e1e_flush();
 }
 
@@ -1552,9 +1831,8 @@ void e1000e_free_rx_resources(struct e1000_adapter *adapter)
  *      traffic pattern.  Constants in this function were computed
  *      based on theoretical maximum wire speed and thresholds were set based
  *      on testing data as well as attempting to minimize response time
- *      while increasing bulk throughput.
- *      this functionality is controlled by the InterruptThrottleRate module
- *      parameter (see e1000_param.c)
+ *      while increasing bulk throughput.  This functionality is controlled
+ *      by the InterruptThrottleRate module parameter.
  **/
 static unsigned int e1000_update_itr(struct e1000_adapter *adapter,
 				     u16 itr_setting, int packets,
@@ -1662,11 +1940,37 @@ set_itr_now:
 			     min(adapter->itr + (new_itr >> 2), new_itr) :
 			     new_itr;
 		adapter->itr = new_itr;
-		ew32(ITR, 1000000000 / (new_itr * 256));
+		adapter->rx_ring->itr_val = new_itr;
+		if (adapter->msix_entries)
+			adapter->rx_ring->set_itr = 1;
+		else
+			ew32(ITR, 1000000000 / (new_itr * 256));
 	}
 }
 
 /**
+ * e1000_alloc_queues - Allocate memory for all rings
+ * @adapter: board private structure to initialize
+ **/
+static int __devinit e1000_alloc_queues(struct e1000_adapter *adapter)
+{
+	adapter->tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
+	if (!adapter->tx_ring)
+		goto err;
+
+	adapter->rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
+	if (!adapter->rx_ring)
+		goto err;
+
+	return 0;
+err:
+	e_err("Unable to allocate memory for queues\n");
+	kfree(adapter->rx_ring);
+	kfree(adapter->tx_ring);
+	return -ENOMEM;
+}
+
+/**
  * e1000_clean - NAPI Rx polling callback
  * @napi: struct associated with this polling callback
  * @budget: amount of packets driver is allowed to process this poll
@@ -1674,12 +1978,17 @@ set_itr_now:
 static int e1000_clean(struct napi_struct *napi, int budget)
 {
 	struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi);
+	struct e1000_hw *hw = &adapter->hw;
 	struct net_device *poll_dev = adapter->netdev;
 	int tx_cleaned = 0, work_done = 0;
 
 	/* Must NOT use netdev_priv macro here. */
 	adapter = poll_dev->priv;
 
+	if (adapter->msix_entries &&
+	    !(adapter->rx_ring->ims_val & adapter->tx_ring->ims_val))
+		goto clean_rx;
+
 	/*
 	 * e1000_clean is called per-cpu.  This lock protects
 	 * tx_ring from being cleaned by multiple cpus
@@ -1691,6 +2000,7 @@ static int e1000_clean(struct napi_struct *napi, int budget)
 		spin_unlock(&adapter->tx_queue_lock);
 	}
 
+clean_rx:
 	adapter->clean_rx(adapter, &work_done, budget);
 
 	if (tx_cleaned)
@@ -1701,7 +2011,10 @@ static int e1000_clean(struct napi_struct *napi, int budget)
 		if (adapter->itr_setting & 3)
 			e1000_set_itr(adapter);
 		netif_rx_complete(poll_dev, napi);
-		e1000_irq_enable(adapter);
+		if (adapter->msix_entries)
+			ew32(IMS, adapter->rx_ring->ims_val);
+		else
+			e1000_irq_enable(adapter);
 	}
 
 	return work_done;
@@ -2497,6 +2810,8 @@ int e1000e_up(struct e1000_adapter *adapter)
 	clear_bit(__E1000_DOWN, &adapter->state);
 
 	napi_enable(&adapter->napi);
+	if (adapter->msix_entries)
+		e1000_configure_msix(adapter);
 	e1000_irq_enable(adapter);
 
 	/* fire a link change interrupt to start the watchdog */
@@ -2580,13 +2895,10 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter)
 	adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
 	adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
 
-	adapter->tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
-	if (!adapter->tx_ring)
-		goto err;
+	e1000e_set_interrupt_capability(adapter);
 
-	adapter->rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
-	if (!adapter->rx_ring)
-		goto err;
+	if (e1000_alloc_queues(adapter))
+		return -ENOMEM;
 
 	spin_lock_init(&adapter->tx_queue_lock);
 
@@ -2597,12 +2909,6 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter)
 
 	set_bit(__E1000_DOWN, &adapter->state);
 	return 0;
-
-err:
-	e_err("Unable to allocate memory for queues\n");
-	kfree(adapter->rx_ring);
-	kfree(adapter->tx_ring);
-	return -ENOMEM;
 }
 
 /**
@@ -2644,6 +2950,7 @@ static int e1000_test_msi_interrupt(struct e1000_adapter *adapter)
 
 	/* free the real vector and request a test handler */
 	e1000_free_irq(adapter);
+	e1000e_reset_interrupt_capability(adapter);
 
 	/* Assume that the test fails, if it succeeds then the test
 	 * MSI irq handler will unset this flag */
@@ -2674,6 +2981,7 @@ static int e1000_test_msi_interrupt(struct e1000_adapter *adapter)
 	rmb();
 
 	if (adapter->flags & FLAG_MSI_TEST_FAILED) {
+		adapter->int_mode = E1000E_INT_MODE_LEGACY;
 		err = -EIO;
 		e_info("MSI interrupt test failed!\n");
 	}
@@ -2687,7 +2995,7 @@ static int e1000_test_msi_interrupt(struct e1000_adapter *adapter)
 	/* okay so the test worked, restore settings */
 	e_dbg("%s: MSI interrupt test succeeded!\n", netdev->name);
 msi_test_failed:
-	/* restore the original vector, even if it failed */
+	e1000e_set_interrupt_capability(adapter);
 	e1000_request_irq(adapter);
 	return err;
 }
@@ -2797,7 +3105,7 @@ static int e1000_open(struct net_device *netdev)
 	 * ignore e1000e MSI messages, which means we need to test our MSI
 	 * interrupt now
 	 */
-	{
+	if (adapter->int_mode != E1000E_INT_MODE_LEGACY) {
 		err = e1000_test_msi(adapter);
 		if (err) {
 			e_err("Interrupt allocation failed\n");
@@ -2989,7 +3297,8 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
 
 	adapter->stats.algnerrc += er32(ALGNERRC);
 	adapter->stats.rxerrc += er32(RXERRC);
-	adapter->stats.tncrs += er32(TNCRS);
+	if (hw->mac.type != e1000_82574)
+		adapter->stats.tncrs += er32(TNCRS);
 	adapter->stats.cexterr += er32(CEXTERR);
 	adapter->stats.tsctc += er32(TSCTC);
 	adapter->stats.tsctfc += er32(TSCTFC);
@@ -3337,7 +3646,10 @@ link_up:
 	}
 
 	/* Cause software interrupt to ensure Rx ring is cleaned */
-	ew32(ICS, E1000_ICS_RXDMT0);
+	if (adapter->msix_entries)
+		ew32(ICS, adapter->rx_ring->ims_val);
+	else
+		ew32(ICS, E1000_ICS_RXDMT0);
 
 	/* Force detection of hung controller every watchdog period */
 	adapter->detect_tx_hung = 1;
@@ -4054,6 +4366,7 @@ static int e1000_suspend(struct pci_dev *pdev, pm_message_t state)
 		e1000e_down(adapter);
 		e1000_free_irq(adapter);
 	}
+	e1000e_reset_interrupt_capability(adapter);
 
 	retval = pci_save_state(pdev);
 	if (retval)
@@ -4180,6 +4493,7 @@ static int e1000_resume(struct pci_dev *pdev)
 	pci_enable_wake(pdev, PCI_D3hot, 0);
 	pci_enable_wake(pdev, PCI_D3cold, 0);
 
+	e1000e_set_interrupt_capability(adapter);
 	if (netif_running(netdev)) {
 		err = e1000_request_irq(adapter);
 		if (err)
@@ -4489,6 +4803,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
 
 	adapter->bd_number = cards_found++;
 
+	e1000e_check_options(adapter);
+
 	/* setup adapter struct */
 	err = e1000_sw_init(adapter);
 	if (err)
@@ -4595,8 +4911,6 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
 	INIT_WORK(&adapter->reset_task, e1000_reset_task);
 	INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task);
 
-	e1000e_check_options(adapter);
-
 	/* Initialize link parameters. User can change them with ethtool */
 	adapter->hw.mac.autoneg = 1;
 	adapter->fc_autoneg = 1;
@@ -4726,6 +5040,7 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
 	if (!e1000_check_reset_block(&adapter->hw))
 		e1000_phy_hw_reset(&adapter->hw);
 
+	e1000e_reset_interrupt_capability(adapter);
 	kfree(adapter->tx_ring);
 	kfree(adapter->rx_ring);
 
@@ -4767,6 +5082,8 @@ static struct pci_device_id e1000_pci_tbl[] = {
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E_IAMT), board_82573 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82573L), board_82573 },
 
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82574L), board_82574 },
+
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_DPT),
 	  board_80003es2lan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_SPT),
diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c
index ed912e0..f46db6c 100644
--- a/drivers/net/e1000e/param.c
+++ b/drivers/net/e1000e/param.c
@@ -114,6 +114,15 @@ E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate");
 #define DEFAULT_ITR 3
 #define MAX_ITR 100000
 #define MIN_ITR 100
+/* IntMode (Interrupt Mode)
+ *
+ * Valid Range: 0 - 2
+ *
+ * Default Value: 2 (MSI-X)
+ */
+E1000_PARAM(IntMode, "Interrupt Mode");
+#define MAX_INTMODE	2
+#define MIN_INTMODE	0
 
 /*
  * Enable Smart Power Down of the PHY
@@ -352,6 +361,24 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
 			adapter->itr = 20000;
 		}
 	}
+	{ /* Interrupt Mode */
+		struct e1000_option opt = {
+			.type = range_option,
+			.name = "Interrupt Mode",
+			.err  = "defaulting to 2 (MSI-X)",
+			.def  = E1000E_INT_MODE_MSIX,
+			.arg  = { .r = { .min = MIN_INTMODE,
+					 .max = MAX_INTMODE } }
+		};
+
+		if (num_IntMode > bd) {
+			unsigned int int_mode = IntMode[bd];
+			e1000_validate_option(&int_mode, &opt, adapter);
+			adapter->int_mode = int_mode;
+		} else {
+			adapter->int_mode = opt.def;
+		}
+	}
 	{ /* Smart Power Down */
 		const struct e1000_option opt = {
 			.type = enable_option,
diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c
index 16724f8..6cd333a 100644
--- a/drivers/net/e1000e/phy.c
+++ b/drivers/net/e1000e/phy.c
@@ -476,7 +476,9 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
 	if (ret_val)
 		return ret_val;
 
-	if ((phy->type == e1000_phy_m88) && (phy->revision < 4)) {
+	if ((phy->type == e1000_phy_m88) &&
+	    (phy->revision < E1000_REVISION_4) &&
+	    (phy->id != BME1000_E_PHY_ID_R2)) {
 		/*
 		 * Force TX_CLK in the Extended PHY Specific Control Register
 		 * to 25MHz clock.
@@ -504,6 +506,18 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
 			return ret_val;
 	}
 
+	if ((phy->type == e1000_phy_bm) && (phy->id == BME1000_E_PHY_ID_R2)) {
+		/* Set PHY page 0, register 29 to 0x0003 */
+		ret_val = e1e_wphy(hw, 29, 0x0003);
+		if (ret_val)
+			return ret_val;
+
+		/* Set PHY page 0, register 30 to 0x0000 */
+		ret_val = e1e_wphy(hw, 30, 0x0000);
+		if (ret_val)
+			return ret_val;
+	}
+
 	/* Commit the changes. */
 	ret_val = e1000e_commit_phy(hw);
 	if (ret_val)
@@ -2054,6 +2068,99 @@ out:
 }
 
 /**
+ *  e1000e_read_phy_reg_bm2 - Read BM 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.
+ **/
+s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	s32 ret_val;
+	u16 page = (u16)(offset >> IGP_PAGE_SHIFT);
+
+	/* Page 800 works differently than the rest so it has its own func */
+	if (page == BM_WUC_PAGE) {
+		ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data,
+							 true);
+		return ret_val;
+	}
+
+	ret_val = hw->phy.ops.acquire_phy(hw);
+	if (ret_val)
+		return ret_val;
+
+	hw->phy.addr = 1;
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+
+		/* Page is shifted left, PHY expects (page x 32) */
+		ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
+						    page);
+
+		if (ret_val) {
+			hw->phy.ops.release_phy(hw);
+			return ret_val;
+		}
+	}
+
+	ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+					   data);
+	hw->phy.ops.release_phy(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_write_phy_reg_bm2 - Write BM PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore, if necessary, then writes the data to PHY register
+ *  at the offset.  Release any acquired semaphores before exiting.
+ **/
+s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	s32 ret_val;
+	u16 page = (u16)(offset >> IGP_PAGE_SHIFT);
+
+	/* Page 800 works differently than the rest so it has its own func */
+	if (page == BM_WUC_PAGE) {
+		ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data,
+							 false);
+		return ret_val;
+	}
+
+	ret_val = hw->phy.ops.acquire_phy(hw);
+	if (ret_val)
+		return ret_val;
+
+	hw->phy.addr = 1;
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+		/* Page is shifted left, PHY expects (page x 32) */
+		ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
+						    page);
+
+		if (ret_val) {
+			hw->phy.ops.release_phy(hw);
+			return ret_val;
+		}
+	}
+
+	ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+					    data);
+
+	hw->phy.ops.release_phy(hw);
+
+	return ret_val;
+}
+
+/**
  *  e1000_access_phy_wakeup_reg_bm - Read BM PHY wakeup register
  *  @hw: pointer to the HW structure
  *  @offset: register offset to be read or written


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

* Re: [UPDATED PATCH] e1000e: add support for new 82574L part
  2008-08-13  7:30 [UPDATED PATCH] e1000e: add support for new 82574L part Jeff Kirsher
@ 2008-08-13 15:29 ` Arthur Jones
  2008-08-13 20:53   ` Jeff Kirsher
  0 siblings, 1 reply; 3+ messages in thread
From: Arthur Jones @ 2008-08-13 15:29 UTC (permalink / raw)
  To: Jeff Kirsher
  Cc: jeff@garzik.org, netdev@vger.kernel.org,
	akpm@linux-foundation.org, Bruce Allan

Hi Jeff,  This patch doesn't apply for me as
it seems to be tab -> space mangled...

Arthur

On Wed, Aug 13, 2008 at 12:30:18AM -0700, Jeff Kirsher wrote:
> From: Bruce Allan <bruce.w.allan@intel.com>
> 
> This new part has the same feature set as previous parts with the addition
> of MSI-X support.
> 
> Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
> ---
> 
>  drivers/net/e1000e/82571.c   |  153 ++++++++++++++--
>  drivers/net/e1000e/defines.h |   13 +
>  drivers/net/e1000e/e1000.h   |   28 +++
>  drivers/net/e1000e/es2lan.c  |    2
>  drivers/net/e1000e/ethtool.c |   38 +++-
>  drivers/net/e1000e/hw.h      |   11 +
>  drivers/net/e1000e/ich8lan.c |   18 ++
>  drivers/net/e1000e/lib.c     |    7 -
>  drivers/net/e1000e/netdev.c  |  409 +++++++++++++++++++++++++++++++++++++-----
>  drivers/net/e1000e/param.c   |   27 +++
>  drivers/net/e1000e/phy.c     |  109 +++++++++++
>  11 files changed, 738 insertions(+), 77 deletions(-)
> 
> diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c
> index 462351c..b2c910c 100644
> --- a/drivers/net/e1000e/82571.c
> +++ b/drivers/net/e1000e/82571.c
> @@ -38,6 +38,7 @@
>   * 82573V Gigabit Ethernet Controller (Copper)
>   * 82573E Gigabit Ethernet Controller (Copper)
>   * 82573L Gigabit Ethernet Controller
> + * 82574L Gigabit Network Connection
>   */
> 
>  #include <linux/netdevice.h>
> @@ -54,6 +55,8 @@
> 
>  #define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
> 
> +#define E1000_NVM_INIT_CTRL2_MNGM 0x6000 /* Manageability Operation Mode mask */
> +
>  static s32 e1000_get_phy_id_82571(struct e1000_hw *hw);
>  static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw);
>  static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw);
> @@ -63,6 +66,8 @@ static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw);
>  static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw);
>  static s32 e1000_setup_link_82571(struct e1000_hw *hw);
>  static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw);
> +static bool e1000_check_mng_mode_82574(struct e1000_hw *hw);
> +static s32 e1000_led_on_82574(struct e1000_hw *hw);
> 
>  /**
>   *  e1000_init_phy_params_82571 - Init PHY func ptrs.
> @@ -92,6 +97,9 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
>         case e1000_82573:
>                 phy->type                = e1000_phy_m88;
>                 break;
> +       case e1000_82574:
> +               phy->type                = e1000_phy_bm;
> +               break;
>         default:
>                 return -E1000_ERR_PHY;
>                 break;
> @@ -111,6 +119,10 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
>                 if (phy->id != M88E1111_I_PHY_ID)
>                         return -E1000_ERR_PHY;
>                 break;
> +       case e1000_82574:
> +               if (phy->id != BME1000_E_PHY_ID_R2)
> +                       return -E1000_ERR_PHY;
> +               break;
>         default:
>                 return -E1000_ERR_PHY;
>                 break;
> @@ -150,6 +162,7 @@ static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw)
> 
>         switch (hw->mac.type) {
>         case e1000_82573:
> +       case e1000_82574:
>                 if (((eecd >> 15) & 0x3) == 0x3) {
>                         nvm->type = e1000_nvm_flash_hw;
>                         nvm->word_size = 2048;
> @@ -245,6 +258,17 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
>                 break;
>         }
> 
> +       switch (hw->mac.type) {
> +       case e1000_82574:
> +               func->check_mng_mode = e1000_check_mng_mode_82574;
> +               func->led_on = e1000_led_on_82574;
> +               break;
> +       default:
> +               func->check_mng_mode = e1000e_check_mng_mode_generic;
> +               func->led_on = e1000e_led_on_generic;
> +               break;
> +       }
> +
>         return 0;
>  }
> 
> @@ -330,6 +354,8 @@ static s32 e1000_get_variants_82571(struct e1000_adapter *adapter)
>  static s32 e1000_get_phy_id_82571(struct e1000_hw *hw)
>  {
>         struct e1000_phy_info *phy = &hw->phy;
> +       s32 ret_val;
> +       u16 phy_id = 0;
> 
>         switch (hw->mac.type) {
>         case e1000_82571:
> @@ -345,6 +371,20 @@ static s32 e1000_get_phy_id_82571(struct e1000_hw *hw)
>         case e1000_82573:
>                 return e1000e_get_phy_id(hw);
>                 break;
> +       case e1000_82574:
> +               ret_val = e1e_rphy(hw, PHY_ID1, &phy_id);
> +               if (ret_val)
> +                       return ret_val;
> +
> +               phy->id = (u32)(phy_id << 16);
> +               udelay(20);
> +               ret_val = e1e_rphy(hw, PHY_ID2, &phy_id);
> +               if (ret_val)
> +                       return ret_val;
> +
> +               phy->id |= (u32)(phy_id);
> +               phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
> +               break;
>         default:
>                 return -E1000_ERR_PHY;
>                 break;
> @@ -421,7 +461,7 @@ static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw)
>         if (ret_val)
>                 return ret_val;
> 
> -       if (hw->mac.type != e1000_82573)
> +       if (hw->mac.type != e1000_82573 && hw->mac.type != e1000_82574)
>                 ret_val = e1000e_acquire_nvm(hw);
> 
>         if (ret_val)
> @@ -461,6 +501,7 @@ static s32 e1000_write_nvm_82571(struct e1000_hw *hw, u16 offset, u16 words,
> 
>         switch (hw->mac.type) {
>         case e1000_82573:
> +       case e1000_82574:
>                 ret_val = e1000_write_nvm_eewr_82571(hw, offset, words, data);
>                 break;
>         case e1000_82571:
> @@ -735,7 +776,7 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
>          * Must acquire the MDIO ownership before MAC reset.
>          * Ownership defaults to firmware after a reset.
>          */
> -       if (hw->mac.type == e1000_82573) {
> +       if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
>                 extcnf_ctrl = er32(EXTCNF_CTRL);
>                 extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
> 
> @@ -776,7 +817,7 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
>          * Need to wait for Phy configuration completion before accessing
>          * NVM and Phy.
>          */
> -       if (hw->mac.type == e1000_82573)
> +       if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574)
>                 msleep(25);
> 
>         /* Clear any pending interrupt events. */
> @@ -843,7 +884,7 @@ static s32 e1000_init_hw_82571(struct e1000_hw *hw)
>         ew32(TXDCTL(0), reg_data);
> 
>         /* ...for both queues. */
> -       if (mac->type != e1000_82573) {
> +       if (mac->type != e1000_82573 && mac->type != e1000_82574) {
>                 reg_data = er32(TXDCTL(1));
>                 reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
>                            E1000_TXDCTL_FULL_TX_DESC_WB |
> @@ -918,19 +959,28 @@ static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw)
>         }
> 
>         /* Device Control */
> -       if (hw->mac.type == e1000_82573) {
> +       if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
>                 reg = er32(CTRL);
>                 reg &= ~(1 << 29);
>                 ew32(CTRL, reg);
>         }
> 
>         /* Extended Device Control */
> -       if (hw->mac.type == e1000_82573) {
> +       if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
>                 reg = er32(CTRL_EXT);
>                 reg &= ~(1 << 23);
>                 reg |= (1 << 22);
>                 ew32(CTRL_EXT, reg);
>         }
> +
> +       /* PCI-Ex Control Register */
> +       if (hw->mac.type == e1000_82574) {
> +               reg = er32(GCR);
> +               reg |= (1 << 22);
> +               ew32(GCR, reg);
> +       }
> +
> +       return;
>  }
> 
>  /**
> @@ -947,7 +997,7 @@ void e1000e_clear_vfta(struct e1000_hw *hw)
>         u32 vfta_offset = 0;
>         u32 vfta_bit_in_reg = 0;
> 
> -       if (hw->mac.type == e1000_82573) {
> +       if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
>                 if (hw->mng_cookie.vlan_id != 0) {
>                         /*
>                          * The VFTA is a 4096b bit-field, each identifying
> @@ -976,6 +1026,48 @@ void e1000e_clear_vfta(struct e1000_hw *hw)
>  }
> 
>  /**
> + *  e1000_check_mng_mode_82574 - Check manageability is enabled
> + *  @hw: pointer to the HW structure
> + *
> + *  Reads the NVM Initialization Control Word 2 and returns true
> + *  (>0) if any manageability is enabled, else false (0).
> + **/
> +static bool e1000_check_mng_mode_82574(struct e1000_hw *hw)
> +{
> +       u16 data;
> +
> +       e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &data);
> +       return (data & E1000_NVM_INIT_CTRL2_MNGM) != 0;
> +}
> +
> +/**
> + *  e1000_led_on_82574 - Turn LED on
> + *  @hw: pointer to the HW structure
> + *
> + *  Turn LED on.
> + **/
> +static s32 e1000_led_on_82574(struct e1000_hw *hw)
> +{
> +       u32 ctrl;
> +       u32 i;
> +
> +       ctrl = hw->mac.ledctl_mode2;
> +       if (!(E1000_STATUS_LU & er32(STATUS))) {
> +               /*
> +                * If no link, then turn LED on by setting the invert bit
> +                * for each LED that's "on" (0x0E) in ledctl_mode2.
> +                */
> +               for (i = 0; i < 4; i++)
> +                       if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
> +                           E1000_LEDCTL_MODE_LED_ON)
> +                               ctrl |= (E1000_LEDCTL_LED0_IVRT << (i * 8));
> +       }
> +       ew32(LEDCTL, ctrl);
> +
> +       return 0;
> +}
> +
> +/**
>   *  e1000_update_mc_addr_list_82571 - Update Multicast addresses
>   *  @hw: pointer to the HW structure
>   *  @mc_addr_list: array of multicast addresses to program
> @@ -1018,7 +1110,8 @@ static s32 e1000_setup_link_82571(struct e1000_hw *hw)
>          * the default flow control setting, so we explicitly
>          * set it to full.
>          */
> -       if (hw->mac.type == e1000_82573)
> +       if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) &&
> +           hw->fc.type == e1000_fc_default)
>                 hw->fc.type = e1000_fc_full;
> 
>         return e1000e_setup_link(hw);
> @@ -1045,6 +1138,7 @@ static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw)
> 
>         switch (hw->phy.type) {
>         case e1000_phy_m88:
> +       case e1000_phy_bm:
>                 ret_val = e1000e_copper_link_setup_m88(hw);
>                 break;
>         case e1000_phy_igp_2:
> @@ -1114,11 +1208,10 @@ static s32 e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data)
>                 return ret_val;
>         }
> 
> -       if (hw->mac.type == e1000_82573 &&
> +       if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) &&
>             *data == ID_LED_RESERVED_F746)
>                 *data = ID_LED_DEFAULT_82573;
> -       else if (*data == ID_LED_RESERVED_0000 ||
> -                *data == ID_LED_RESERVED_FFFF)
> +       else if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
>                 *data = ID_LED_DEFAULT;
> 
>         return 0;
> @@ -1265,13 +1358,13 @@ static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw)
>  }
> 
>  static struct e1000_mac_operations e82571_mac_ops = {
> -       .mng_mode_enab          = E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
> +       /* .check_mng_mode: mac type dependent */
>         /* .check_for_link: media type dependent */
>         .cleanup_led            = e1000e_cleanup_led_generic,
>         .clear_hw_cntrs         = e1000_clear_hw_cntrs_82571,
>         .get_bus_info           = e1000e_get_bus_info_pcie,
>         /* .get_link_up_info: media type dependent */
> -       .led_on                 = e1000e_led_on_generic,
> +       /* .led_on: mac type dependent */
>         .led_off                = e1000e_led_off_generic,
>         .update_mc_addr_list    = e1000_update_mc_addr_list_82571,
>         .reset_hw               = e1000_reset_hw_82571,
> @@ -1312,6 +1405,22 @@ static struct e1000_phy_operations e82_phy_ops_m88 = {
>         .write_phy_reg          = e1000e_write_phy_reg_m88,
>  };
> 
> +static struct e1000_phy_operations e82_phy_ops_bm = {
> +       .acquire_phy            = e1000_get_hw_semaphore_82571,
> +       .check_reset_block      = e1000e_check_reset_block_generic,
> +       .commit_phy             = e1000e_phy_sw_reset,
> +       .force_speed_duplex     = e1000e_phy_force_speed_duplex_m88,
> +       .get_cfg_done           = e1000e_get_cfg_done,
> +       .get_cable_length       = e1000e_get_cable_length_m88,
> +       .get_phy_info           = e1000e_get_phy_info_m88,
> +       .read_phy_reg           = e1000e_read_phy_reg_bm2,
> +       .release_phy            = e1000_put_hw_semaphore_82571,
> +       .reset_phy              = e1000e_phy_hw_reset_generic,
> +       .set_d0_lplu_state      = e1000_set_d0_lplu_state_82571,
> +       .set_d3_lplu_state      = e1000e_set_d3_lplu_state,
> +       .write_phy_reg          = e1000e_write_phy_reg_bm2,
> +};
> +
>  static struct e1000_nvm_operations e82571_nvm_ops = {
>         .acquire_nvm            = e1000_acquire_nvm_82571,
>         .read_nvm               = e1000e_read_nvm_eerd,
> @@ -1375,3 +1484,21 @@ struct e1000_info e1000_82573_info = {
>         .nvm_ops                = &e82571_nvm_ops,
>  };
> 
> +struct e1000_info e1000_82574_info = {
> +       .mac                    = e1000_82574,
> +       .flags                  = FLAG_HAS_HW_VLAN_FILTER
> +                                 | FLAG_HAS_MSIX
> +                                 | FLAG_HAS_JUMBO_FRAMES
> +                                 | FLAG_HAS_WOL
> +                                 | FLAG_APME_IN_CTRL3
> +                                 | FLAG_RX_CSUM_ENABLED
> +                                 | FLAG_HAS_SMART_POWER_DOWN
> +                                 | FLAG_HAS_AMT
> +                                 | FLAG_HAS_CTRLEXT_ON_LOAD,
> +       .pba                    = 20,
> +       .get_variants           = e1000_get_variants_82571,
> +       .mac_ops                = &e82571_mac_ops,
> +       .phy_ops                = &e82_phy_ops_bm,
> +       .nvm_ops                = &e82571_nvm_ops,
> +};
> +
> diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h
> index 4b21fa9..48f79ec 100644
> --- a/drivers/net/e1000e/defines.h
> +++ b/drivers/net/e1000e/defines.h
> @@ -71,9 +71,11 @@
>  #define E1000_CTRL_EXT_RO_DIS    0x00020000 /* Relaxed Ordering disable */
>  #define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
>  #define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES  0x00C00000
> +#define E1000_CTRL_EXT_EIAME          0x01000000
>  #define E1000_CTRL_EXT_DRV_LOAD       0x10000000 /* Driver loaded bit for FW */
>  #define E1000_CTRL_EXT_IAME           0x08000000 /* Interrupt acknowledge Auto-mask */
>  #define E1000_CTRL_EXT_INT_TIMER_CLR  0x20000000 /* Clear Interrupt timers after IMS clear */
> +#define E1000_CTRL_EXT_PBA_CLR        0x80000000 /* PBA Clear */
> 
>  /* Receive Descriptor bit definitions */
>  #define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
> @@ -299,6 +301,7 @@
>  #define E1000_RXCSUM_IPPCSE    0x00001000   /* IP payload checksum enable */
> 
>  /* Header split receive */
> +#define E1000_RFCTL_ACK_DIS             0x00001000
>  #define E1000_RFCTL_EXTEN               0x00008000
>  #define E1000_RFCTL_IPV6_EX_DIS         0x00010000
>  #define E1000_RFCTL_NEW_IPV6_EXT_DIS    0x00020000
> @@ -363,6 +366,11 @@
>  #define E1000_ICR_RXDMT0        0x00000010 /* Rx desc min. threshold (0) */
>  #define E1000_ICR_RXT0          0x00000080 /* Rx timer intr (ring 0) */
>  #define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver should claim the interrupt */
> +#define E1000_ICR_RXQ0          0x00100000 /* Rx Queue 0 Interrupt */
> +#define E1000_ICR_RXQ1          0x00200000 /* Rx Queue 1 Interrupt */
> +#define E1000_ICR_TXQ0          0x00400000 /* Tx Queue 0 Interrupt */
> +#define E1000_ICR_TXQ1          0x00800000 /* Tx Queue 1 Interrupt */
> +#define E1000_ICR_OTHER         0x01000000 /* Other Interrupts */
> 
>  /*
>   * This defines the bits that are set in the Interrupt Mask
> @@ -386,6 +394,11 @@
>  #define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* Rx sequence error */
>  #define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* Rx desc min. threshold */
>  #define E1000_IMS_RXT0      E1000_ICR_RXT0      /* Rx timer intr */
> +#define E1000_IMS_RXQ0      E1000_ICR_RXQ0      /* Rx Queue 0 Interrupt */
> +#define E1000_IMS_RXQ1      E1000_ICR_RXQ1      /* Rx Queue 1 Interrupt */
> +#define E1000_IMS_TXQ0      E1000_ICR_TXQ0      /* Tx Queue 0 Interrupt */
> +#define E1000_IMS_TXQ1      E1000_ICR_TXQ1      /* Tx Queue 1 Interrupt */
> +#define E1000_IMS_OTHER     E1000_ICR_OTHER     /* Other Interrupts */
> 
>  /* Interrupt Cause Set */
>  #define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
> diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
> index ef66dc4..0a1916b 100644
> --- a/drivers/net/e1000e/e1000.h
> +++ b/drivers/net/e1000e/e1000.h
> @@ -62,6 +62,11 @@ struct e1000_info;
>         e_printk(KERN_NOTICE, adapter, format, ## arg)
> 
> 
> +/* Interrupt modes, as used by the IntMode paramter */
> +#define E1000E_INT_MODE_LEGACY         0
> +#define E1000E_INT_MODE_MSI            1
> +#define E1000E_INT_MODE_MSIX           2
> +
>  /* Tx/Rx descriptor defines */
>  #define E1000_DEFAULT_TXD              256
>  #define E1000_MAX_TXD                  4096
> @@ -95,6 +100,7 @@ enum e1000_boards {
>         board_82571,
>         board_82572,
>         board_82573,
> +       board_82574,
>         board_80003es2lan,
>         board_ich8lan,
>         board_ich9lan,
> @@ -147,6 +153,12 @@ struct e1000_ring {
>         /* array of buffer information structs */
>         struct e1000_buffer *buffer_info;
> 
> +       char name[IFNAMSIZ + 5];
> +       u32 ims_val;
> +       u32 itr_val;
> +       u16 itr_register;
> +       int set_itr;
> +
>         struct sk_buff *rx_skb_top;
> 
>         struct e1000_queue_stats stats;
> @@ -275,6 +287,9 @@ struct e1000_adapter {
>         u32 test_icr;
> 
>         u32 msg_enable;
> +       struct msix_entry *msix_entries;
> +       int int_mode;
> +       u32 eiac_mask;
> 
>         u32 eeprom_wol;
>         u32 wol;
> @@ -307,6 +322,7 @@ struct e1000_info {
>  #define FLAG_HAS_SWSM_ON_LOAD             (1 << 6)
>  #define FLAG_HAS_JUMBO_FRAMES             (1 << 7)
>  #define FLAG_IS_ICH                       (1 << 9)
> +#define FLAG_HAS_MSIX                     (1 << 10)
>  #define FLAG_HAS_SMART_POWER_DOWN         (1 << 11)
>  #define FLAG_IS_QUAD_PORT_A               (1 << 12)
>  #define FLAG_IS_QUAD_PORT                 (1 << 13)
> @@ -365,6 +381,8 @@ extern int e1000e_setup_tx_resources(struct e1000_adapter *adapter);
>  extern void e1000e_free_rx_resources(struct e1000_adapter *adapter);
>  extern void e1000e_free_tx_resources(struct e1000_adapter *adapter);
>  extern void e1000e_update_stats(struct e1000_adapter *adapter);
> +extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter);
> +extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter);
> 
>  extern unsigned int copybreak;
> 
> @@ -373,6 +391,7 @@ extern char *e1000e_get_hw_dev_name(struct e1000_hw *hw);
>  extern struct e1000_info e1000_82571_info;
>  extern struct e1000_info e1000_82572_info;
>  extern struct e1000_info e1000_82573_info;
> +extern struct e1000_info e1000_82574_info;
>  extern struct e1000_info e1000_ich8_info;
>  extern struct e1000_info e1000_ich9_info;
>  extern struct e1000_info e1000_ich10_info;
> @@ -453,6 +472,8 @@ extern enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id);
>  extern s32 e1000e_determine_phy_address(struct e1000_hw *hw);
>  extern s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data);
>  extern s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data);
> +extern s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data);
> +extern s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data);
>  extern void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl);
>  extern s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data);
>  extern s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
> @@ -523,7 +544,12 @@ static inline s32 e1000_get_phy_info(struct e1000_hw *hw)
>         return hw->phy.ops.get_phy_info(hw);
>  }
> 
> -extern bool e1000e_check_mng_mode(struct e1000_hw *hw);
> +static inline s32 e1000e_check_mng_mode(struct e1000_hw *hw)
> +{
> +       return hw->mac.ops.check_mng_mode(hw);
> +}
> +
> +extern bool e1000e_check_mng_mode_generic(struct e1000_hw *hw);
>  extern bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw);
>  extern s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length);
> 
> diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c
> index dc552d7..da9c09c 100644
> --- a/drivers/net/e1000e/es2lan.c
> +++ b/drivers/net/e1000e/es2lan.c
> @@ -1247,7 +1247,7 @@ static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw)
>  }
> 
>  static struct e1000_mac_operations es2_mac_ops = {
> -       .mng_mode_enab          = E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
> +       .check_mng_mode         = e1000e_check_mng_mode_generic,
>         /* check_for_link dependent on media type */
>         .cleanup_led            = e1000e_cleanup_led_generic,
>         .clear_hw_cntrs         = e1000_clear_hw_cntrs_80003es2lan,
> diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
> index a89498d..52b762e 100644
> --- a/drivers/net/e1000e/ethtool.c
> +++ b/drivers/net/e1000e/ethtool.c
> @@ -568,6 +568,7 @@ static int e1000_set_eeprom(struct net_device *netdev,
>          * and flush shadow RAM for 82573 controllers
>          */
>         if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG) ||
> +                              (hw->mac.type == e1000_82574) ||
>                                (hw->mac.type == e1000_82573)))
>                 e1000e_update_nvm_checksum(hw);
> 
> @@ -779,6 +780,7 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
>                 toggle = 0x7FFFF3FF;
>                 break;
>         case e1000_82573:
> +       case e1000_82574:
>         case e1000_ich8lan:
>         case e1000_ich9lan:
>         case e1000_ich10lan:
> @@ -887,10 +889,18 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
>         u32 shared_int = 1;
>         u32 irq = adapter->pdev->irq;
>         int i;
> +       int ret_val = 0;
> +       int int_mode = E1000E_INT_MODE_LEGACY;
> 
>         *data = 0;
> 
> -       /* NOTE: we don't test MSI interrupts here, yet */
> +       /* NOTE: we don't test MSI/MSI-X interrupts here, yet */
> +       if (adapter->int_mode == E1000E_INT_MODE_MSIX) {
> +               int_mode = adapter->int_mode;
> +               e1000e_reset_interrupt_capability(adapter);
> +               adapter->int_mode = E1000E_INT_MODE_LEGACY;
> +               e1000e_set_interrupt_capability(adapter);
> +       }
>         /* Hook up test interrupt handler just for this test */
>         if (!request_irq(irq, &e1000_test_intr, IRQF_PROBE_SHARED, netdev->name,
>                          netdev)) {
> @@ -898,7 +908,8 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
>         } else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED,
>                  netdev->name, netdev)) {
>                 *data = 1;
> -               return -1;
> +               ret_val = -1;
> +               goto out;
>         }
>         e_info("testing %s interrupt\n", (shared_int ? "shared" : "unshared"));
> 
> @@ -988,7 +999,14 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
>         /* Unhook test interrupt handler */
>         free_irq(irq, netdev);
> 
> -       return *data;
> +out:
> +       if (int_mode == E1000E_INT_MODE_MSIX) {
> +               e1000e_reset_interrupt_capability(adapter);
> +               adapter->int_mode = int_mode;
> +               e1000e_set_interrupt_capability(adapter);
> +       }
> +
> +       return ret_val;
>  }
> 
>  static void e1000_free_desc_rings(struct e1000_adapter *adapter)
> @@ -1769,11 +1787,13 @@ static void e1000_led_blink_callback(unsigned long data)
>  static int e1000_phys_id(struct net_device *netdev, u32 data)
>  {
>         struct e1000_adapter *adapter = netdev_priv(netdev);
> +       struct e1000_hw *hw = &adapter->hw;
> 
>         if (!data)
>                 data = INT_MAX;
> 
> -       if (adapter->hw.phy.type == e1000_phy_ife) {
> +       if ((hw->phy.type == e1000_phy_ife) ||
> +           (hw->mac.type == e1000_82574)) {
>                 if (!adapter->blink_timer.function) {
>                         init_timer(&adapter->blink_timer);
>                         adapter->blink_timer.function =
> @@ -1783,16 +1803,16 @@ static int e1000_phys_id(struct net_device *netdev, u32 data)
>                 mod_timer(&adapter->blink_timer, jiffies);
>                 msleep_interruptible(data * 1000);
>                 del_timer_sync(&adapter->blink_timer);
> -               e1e_wphy(&adapter->hw,
> -                                   IFE_PHY_SPECIAL_CONTROL_LED, 0);
> +               if (hw->phy.type == e1000_phy_ife)
> +                       e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0);
>         } else {
> -               e1000e_blink_led(&adapter->hw);
> +               e1000e_blink_led(hw);
>                 msleep_interruptible(data * 1000);
>         }
> 
> -       adapter->hw.mac.ops.led_off(&adapter->hw);
> +       hw->mac.ops.led_off(hw);
>         clear_bit(E1000_LED_ON, &adapter->led_status);
> -       adapter->hw.mac.ops.cleanup_led(&adapter->hw);
> +       hw->mac.ops.cleanup_led(hw);
> 
>         return 0;
>  }
> diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h
> index 5d2acc5..f66ed37 100644
> --- a/drivers/net/e1000e/hw.h
> +++ b/drivers/net/e1000e/hw.h
> @@ -65,7 +65,11 @@ enum e1e_registers {
>         E1000_ICS      = 0x000C8, /* Interrupt Cause Set - WO */
>         E1000_IMS      = 0x000D0, /* Interrupt Mask Set - RW */
>         E1000_IMC      = 0x000D8, /* Interrupt Mask Clear - WO */
> +       E1000_EIAC_82574 = 0x000DC, /* Ext. Interrupt Auto Clear - RW */
>         E1000_IAM      = 0x000E0, /* Interrupt Acknowledge Auto Mask */
> +       E1000_IVAR     = 0x000E4, /* Interrupt Vector Allocation - RW */
> +       E1000_EITR_82574_BASE = 0x000E8, /* Interrupt Throttling - RW */
> +#define E1000_EITR_82574(_n) (E1000_EITR_82574_BASE + (_n << 2))
>         E1000_RCTL     = 0x00100, /* Rx Control - RW */
>         E1000_FCTTV    = 0x00170, /* Flow Control Transmit Timer Value - RW */
>         E1000_TXCW     = 0x00178, /* Tx Configuration Word - RW */
> @@ -332,6 +336,7 @@ enum e1e_registers {
>  #define E1000_DEV_ID_82573E                    0x108B
>  #define E1000_DEV_ID_82573E_IAMT               0x108C
>  #define E1000_DEV_ID_82573L                    0x109A
> +#define E1000_DEV_ID_82574L                    0x10D3
> 
>  #define E1000_DEV_ID_80003ES2LAN_COPPER_DPT    0x1096
>  #define E1000_DEV_ID_80003ES2LAN_SERDES_DPT    0x1098
> @@ -360,12 +365,15 @@ enum e1e_registers {
>  #define E1000_DEV_ID_ICH10_D_BM_LM             0x10DE
>  #define E1000_DEV_ID_ICH10_D_BM_LF             0x10DF
> 
> +#define E1000_REVISION_4 4
> +
>  #define E1000_FUNC_1 1
> 
>  enum e1000_mac_type {
>         e1000_82571,
>         e1000_82572,
>         e1000_82573,
> +       e1000_82574,
>         e1000_80003es2lan,
>         e1000_ich8lan,
>         e1000_ich9lan,
> @@ -700,8 +708,7 @@ struct e1000_host_mng_command_info {
> 
>  /* Function pointers and static data for the MAC. */
>  struct e1000_mac_operations {
> -       u32                     mng_mode_enab;
> -
> +       bool (*check_mng_mode)(struct e1000_hw *);
>         s32  (*check_for_link)(struct e1000_hw *);
>         s32  (*cleanup_led)(struct e1000_hw *);
>         void (*clear_hw_cntrs)(struct e1000_hw *);
> diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
> index 0e76bb0..019b9c0 100644
> --- a/drivers/net/e1000e/ich8lan.c
> +++ b/drivers/net/e1000e/ich8lan.c
> @@ -422,6 +422,22 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
>  }
> 
>  /**
> + *  e1000_check_mng_mode_ich8lan - Checks management mode
> + *  @hw: pointer to the HW structure
> + *
> + *  This checks if the adapter has manageability enabled.
> + *  This is a function pointer entry point only called by read/write
> + *  routines for the PHY and NVM parts.
> + **/
> +static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw)
> +{
> +       u32 fwsm = er32(FWSM);
> +
> +       return (fwsm & E1000_FWSM_MODE_MASK) ==
> +               (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
> +}
> +
> +/**
>   *  e1000_check_reset_block_ich8lan - Check if PHY reset is blocked
>   *  @hw: pointer to the HW structure
>   *
> @@ -2400,7 +2416,7 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
>  }
> 
>  static struct e1000_mac_operations ich8_mac_ops = {
> -       .mng_mode_enab          = E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
> +       .check_mng_mode         = e1000_check_mng_mode_ich8lan,
>         .check_for_link         = e1000e_check_for_copper_link,
>         .cleanup_led            = e1000_cleanup_led_ich8lan,
>         .clear_hw_cntrs         = e1000_clear_hw_cntrs_ich8lan,
> diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c
> index f1f4e9d..c733730 100644
> --- a/drivers/net/e1000e/lib.c
> +++ b/drivers/net/e1000e/lib.c
> @@ -2222,17 +2222,18 @@ static s32 e1000_mng_enable_host_if(struct e1000_hw *hw)
>  }
> 
>  /**
> - *  e1000e_check_mng_mode - check management mode
> + *  e1000e_check_mng_mode_generic - check management mode
>   *  @hw: pointer to the HW structure
>   *
>   *  Reads the firmware semaphore register and returns true (>0) if
>   *  manageability is enabled, else false (0).
>   **/
> -bool e1000e_check_mng_mode(struct e1000_hw *hw)
> +bool e1000e_check_mng_mode_generic(struct e1000_hw *hw)
>  {
>         u32 fwsm = er32(FWSM);
> 
> -       return (fwsm & E1000_FWSM_MODE_MASK) == hw->mac.ops.mng_mode_enab;
> +       return (fwsm & E1000_FWSM_MODE_MASK) ==
> +               (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
>  }
> 
>  /**
> diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
> index 2d9bcb0..0925204 100644
> --- a/drivers/net/e1000e/netdev.c
> +++ b/drivers/net/e1000e/netdev.c
> @@ -55,6 +55,7 @@ static const struct e1000_info *e1000_info_tbl[] = {
>         [board_82571]           = &e1000_82571_info,
>         [board_82572]           = &e1000_82572_info,
>         [board_82573]           = &e1000_82573_info,
> +       [board_82574]           = &e1000_82574_info,
>         [board_80003es2lan]     = &e1000_es2_info,
>         [board_ich8lan]         = &e1000_ich8_info,
>         [board_ich9lan]         = &e1000_ich9_info,
> @@ -1180,8 +1181,8 @@ static irqreturn_t e1000_intr(int irq, void *data)
>         struct net_device *netdev = data;
>         struct e1000_adapter *adapter = netdev_priv(netdev);
>         struct e1000_hw *hw = &adapter->hw;
> -
>         u32 rctl, icr = er32(ICR);
> +
>         if (!icr)
>                 return IRQ_NONE;  /* Not our interrupt */
> 
> @@ -1237,6 +1238,263 @@ static irqreturn_t e1000_intr(int irq, void *data)
>         return IRQ_HANDLED;
>  }
> 
> +static irqreturn_t e1000_msix_other(int irq, void *data)
> +{
> +       struct net_device *netdev = data;
> +       struct e1000_adapter *adapter = netdev_priv(netdev);
> +       struct e1000_hw *hw = &adapter->hw;
> +       u32 icr = er32(ICR);
> +
> +       if (!(icr & E1000_ICR_INT_ASSERTED)) {
> +               ew32(IMS, E1000_IMS_OTHER);
> +               return IRQ_NONE;
> +       }
> +
> +       if (icr & adapter->eiac_mask)
> +               ew32(ICS, (icr & adapter->eiac_mask));
> +
> +       if (icr & E1000_ICR_OTHER) {
> +               if (!(icr & E1000_ICR_LSC))
> +                       goto no_link_interrupt;
> +               hw->mac.get_link_status = 1;
> +               /* guard against interrupt when we're going down */
> +               if (!test_bit(__E1000_DOWN, &adapter->state))
> +                       mod_timer(&adapter->watchdog_timer, jiffies + 1);
> +       }
> +
> +no_link_interrupt:
> +       ew32(IMS, E1000_IMS_LSC | E1000_IMS_OTHER);
> +
> +       return IRQ_HANDLED;
> +}
> +
> +
> +static irqreturn_t e1000_intr_msix_tx(int irq, void *data)
> +{
> +       struct net_device *netdev = data;
> +       struct e1000_adapter *adapter = netdev_priv(netdev);
> +       struct e1000_hw *hw = &adapter->hw;
> +       struct e1000_ring *tx_ring = adapter->tx_ring;
> +
> +
> +       adapter->total_tx_bytes = 0;
> +       adapter->total_tx_packets = 0;
> +
> +       if (!e1000_clean_tx_irq(adapter))
> +               /* Ring was not completely cleaned, so fire another interrupt */
> +               ew32(ICS, tx_ring->ims_val);
> +
> +       return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t e1000_intr_msix_rx(int irq, void *data)
> +{
> +       struct net_device *netdev = data;
> +       struct e1000_adapter *adapter = netdev_priv(netdev);
> +
> +       /* Write the ITR value calculated at the end of the
> +        * previous interrupt.
> +        */
> +       if (adapter->rx_ring->set_itr) {
> +               writel(1000000000 / (adapter->rx_ring->itr_val * 256),
> +                      adapter->hw.hw_addr + adapter->rx_ring->itr_register);
> +               adapter->rx_ring->set_itr = 0;
> +       }
> +
> +       if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
> +               adapter->total_rx_bytes = 0;
> +               adapter->total_rx_packets = 0;
> +               __netif_rx_schedule(netdev, &adapter->napi);
> +       }
> +       return IRQ_HANDLED;
> +}
> +
> +/**
> + * e1000_configure_msix - Configure MSI-X hardware
> + *
> + * e1000_configure_msix sets up the hardware to properly
> + * generate MSI-X interrupts.
> + **/
> +static void e1000_configure_msix(struct e1000_adapter *adapter)
> +{
> +       struct e1000_hw *hw = &adapter->hw;
> +       struct e1000_ring *rx_ring = adapter->rx_ring;
> +       struct e1000_ring *tx_ring = adapter->tx_ring;
> +       int vector = 0;
> +       u32 ctrl_ext, ivar = 0;
> +
> +       adapter->eiac_mask = 0;
> +
> +       /* Workaround issue with spurious interrupts on 82574 in MSI-X mode */
> +       if (hw->mac.type == e1000_82574) {
> +               u32 rfctl = er32(RFCTL);
> +               rfctl |= E1000_RFCTL_ACK_DIS;
> +               ew32(RFCTL, rfctl);
> +       }
> +
> +#define E1000_IVAR_INT_ALLOC_VALID     0x8
> +       /* Configure Rx vector */
> +       rx_ring->ims_val = E1000_IMS_RXQ0;
> +       adapter->eiac_mask |= rx_ring->ims_val;
> +       if (rx_ring->itr_val)
> +               writel(1000000000 / (rx_ring->itr_val * 256),
> +                      hw->hw_addr + rx_ring->itr_register);
> +       else
> +               writel(1, hw->hw_addr + rx_ring->itr_register);
> +       ivar = E1000_IVAR_INT_ALLOC_VALID | vector;
> +
> +       /* Configure Tx vector */
> +       tx_ring->ims_val = E1000_IMS_TXQ0;
> +       vector++;
> +       if (tx_ring->itr_val)
> +               writel(1000000000 / (tx_ring->itr_val * 256),
> +                      hw->hw_addr + tx_ring->itr_register);
> +       else
> +               writel(1, hw->hw_addr + tx_ring->itr_register);
> +       adapter->eiac_mask |= tx_ring->ims_val;
> +       ivar |= ((E1000_IVAR_INT_ALLOC_VALID | vector) << 8);
> +
> +       /* set vector for Other Causes, e.g. link changes */
> +       vector++;
> +       ivar |= ((E1000_IVAR_INT_ALLOC_VALID | vector) << 16);
> +       if (rx_ring->itr_val)
> +               writel(1000000000 / (rx_ring->itr_val * 256),
> +                      hw->hw_addr + E1000_EITR_82574(vector));
> +       else
> +               writel(1, hw->hw_addr + E1000_EITR_82574(vector));
> +
> +       /* Cause Tx interrupts on every write back */
> +       ivar |= (1 << 31);
> +
> +       ew32(IVAR, ivar);
> +
> +       /* enable MSI-X PBA support */
> +       ctrl_ext = er32(CTRL_EXT);
> +       ctrl_ext |= E1000_CTRL_EXT_PBA_CLR;
> +
> +       /* Auto-Mask Other interrupts upon ICR read */
> +#define E1000_EIAC_MASK_82574   0x01F00000
> +       ew32(IAM, ~E1000_EIAC_MASK_82574 | E1000_IMS_OTHER);
> +       ctrl_ext |= E1000_CTRL_EXT_EIAME;
> +       ew32(CTRL_EXT, ctrl_ext);
> +       e1e_flush();
> +}
> +
> +void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter)
> +{
> +       if (adapter->msix_entries) {
> +               pci_disable_msix(adapter->pdev);
> +               kfree(adapter->msix_entries);
> +               adapter->msix_entries = NULL;
> +       } else if (adapter->flags & FLAG_MSI_ENABLED) {
> +               pci_disable_msi(adapter->pdev);
> +               adapter->flags &= ~FLAG_MSI_ENABLED;
> +       }
> +
> +       return;
> +}
> +
> +/**
> + * e1000e_set_interrupt_capability - set MSI or MSI-X if supported
> + *
> + * Attempt to configure interrupts using the best available
> + * capabilities of the hardware and kernel.
> + **/
> +void e1000e_set_interrupt_capability(struct e1000_adapter *adapter)
> +{
> +       int err;
> +       int numvecs, i;
> +
> +
> +       switch (adapter->int_mode) {
> +       case E1000E_INT_MODE_MSIX:
> +               if (adapter->flags & FLAG_HAS_MSIX) {
> +                       numvecs = 3; /* RxQ0, TxQ0 and other */
> +                       adapter->msix_entries = kcalloc(numvecs,
> +                                                     sizeof(struct msix_entry),
> +                                                     GFP_KERNEL);
> +                       if (adapter->msix_entries) {
> +                               for (i = 0; i < numvecs; i++)
> +                                       adapter->msix_entries[i].entry = i;
> +
> +                               err = pci_enable_msix(adapter->pdev,
> +                                                     adapter->msix_entries,
> +                                                     numvecs);
> +                               if (err == 0)
> +                                       return;
> +                       }
> +                       /* MSI-X failed, so fall through and try MSI */
> +                       e_err("Failed to initialize MSI-X interrupts.  "
> +                             "Falling back to MSI interrupts.\n");
> +                       e1000e_reset_interrupt_capability(adapter);
> +               }
> +               adapter->int_mode = E1000E_INT_MODE_MSI;
> +               /* Fall through */
> +       case E1000E_INT_MODE_MSI:
> +               if (!pci_enable_msi(adapter->pdev)) {
> +                       adapter->flags |= FLAG_MSI_ENABLED;
> +               } else {
> +                       adapter->int_mode = E1000E_INT_MODE_LEGACY;
> +                       e_err("Failed to initialize MSI interrupts.  Falling "
> +                             "back to legacy interrupts.\n");
> +               }
> +               /* Fall through */
> +       case E1000E_INT_MODE_LEGACY:
> +               /* Don't do anything; this is the system default */
> +               break;
> +       }
> +
> +       return;
> +}
> +
> +/**
> + * e1000_request_msix - Initialize MSI-X interrupts
> + *
> + * e1000_request_msix allocates MSI-X vectors and requests interrupts from the
> + * kernel.
> + **/
> +static int e1000_request_msix(struct e1000_adapter *adapter)
> +{
> +       struct net_device *netdev = adapter->netdev;
> +       int err = 0, vector = 0;
> +
> +       if (strlen(netdev->name) < (IFNAMSIZ - 5))
> +               sprintf(adapter->rx_ring->name, "%s-rx0", netdev->name);
> +       else
> +               memcpy(adapter->rx_ring->name, netdev->name, IFNAMSIZ);
> +       err = request_irq(adapter->msix_entries[vector].vector,
> +                         &e1000_intr_msix_rx, 0, adapter->rx_ring->name,
> +                         netdev);
> +       if (err)
> +               goto out;
> +       adapter->rx_ring->itr_register = E1000_EITR_82574(vector);
> +       adapter->rx_ring->itr_val = adapter->itr;
> +       vector++;
> +
> +       if (strlen(netdev->name) < (IFNAMSIZ - 5))
> +               sprintf(adapter->tx_ring->name, "%s-tx0", netdev->name);
> +       else
> +               memcpy(adapter->tx_ring->name, netdev->name, IFNAMSIZ);
> +       err = request_irq(adapter->msix_entries[vector].vector,
> +                         &e1000_intr_msix_tx, 0, adapter->tx_ring->name,
> +                         netdev);
> +       if (err)
> +               goto out;
> +       adapter->tx_ring->itr_register = E1000_EITR_82574(vector);
> +       adapter->tx_ring->itr_val = adapter->itr;
> +       vector++;
> +
> +       err = request_irq(adapter->msix_entries[vector].vector,
> +                         &e1000_msix_other, 0, netdev->name, netdev);
> +       if (err)
> +               goto out;
> +
> +       e1000_configure_msix(adapter);
> +       return 0;
> +out:
> +       return err;
> +}
> +
>  /**
>   * e1000_request_irq - initialize interrupts
>   *
> @@ -1246,29 +1504,33 @@ static irqreturn_t e1000_intr(int irq, void *data)
>  static int e1000_request_irq(struct e1000_adapter *adapter)
>  {
>         struct net_device *netdev = adapter->netdev;
> -       int irq_flags = IRQF_SHARED;
>         int err;
> 
> -       if (!(adapter->flags & FLAG_MSI_TEST_FAILED)) {
> -               err = pci_enable_msi(adapter->pdev);
> -               if (!err) {
> -                       adapter->flags |= FLAG_MSI_ENABLED;
> -                       irq_flags = 0;
> -               }
> +       if (adapter->msix_entries) {
> +               err = e1000_request_msix(adapter);
> +               if (!err)
> +                       return err;
> +               /* fall back to MSI */
> +               e1000e_reset_interrupt_capability(adapter);
> +               adapter->int_mode = E1000E_INT_MODE_MSI;
> +               e1000e_set_interrupt_capability(adapter);
>         }
> +       if (adapter->flags & FLAG_MSI_ENABLED) {
> +               err = request_irq(adapter->pdev->irq, &e1000_intr_msi, 0,
> +                                 netdev->name, netdev);
> +               if (!err)
> +                       return err;
> 
> -       err = request_irq(adapter->pdev->irq,
> -                         ((adapter->flags & FLAG_MSI_ENABLED) ?
> -                               &e1000_intr_msi : &e1000_intr),
> -                         irq_flags, netdev->name, netdev);
> -       if (err) {
> -               if (adapter->flags & FLAG_MSI_ENABLED) {
> -                       pci_disable_msi(adapter->pdev);
> -                       adapter->flags &= ~FLAG_MSI_ENABLED;
> -               }
> -               e_err("Unable to allocate interrupt, Error: %d\n", err);
> +               /* fall back to legacy interrupt */
> +               e1000e_reset_interrupt_capability(adapter);
> +               adapter->int_mode = E1000E_INT_MODE_LEGACY;
>         }
> 
> +       err = request_irq(adapter->pdev->irq, &e1000_intr, IRQF_SHARED,
> +                         netdev->name, netdev);
> +       if (err)
> +               e_err("Unable to allocate interrupt, Error: %d\n", err);
> +
>         return err;
>  }
> 
> @@ -1276,11 +1538,21 @@ static void e1000_free_irq(struct e1000_adapter *adapter)
>  {
>         struct net_device *netdev = adapter->netdev;
> 
> -       free_irq(adapter->pdev->irq, netdev);
> -       if (adapter->flags & FLAG_MSI_ENABLED) {
> -               pci_disable_msi(adapter->pdev);
> -               adapter->flags &= ~FLAG_MSI_ENABLED;
> +       if (adapter->msix_entries) {
> +               int vector = 0;
> +
> +               free_irq(adapter->msix_entries[vector].vector, netdev);
> +               vector++;
> +
> +               free_irq(adapter->msix_entries[vector].vector, netdev);
> +               vector++;
> +
> +               /* Other Causes interrupt vector */
> +               free_irq(adapter->msix_entries[vector].vector, netdev);
> +               return;
>         }
> +
> +       free_irq(adapter->pdev->irq, netdev);
>  }
> 
>  /**
> @@ -1291,6 +1563,8 @@ static void e1000_irq_disable(struct e1000_adapter *adapter)
>         struct e1000_hw *hw = &adapter->hw;
> 
>         ew32(IMC, ~0);
> +       if (adapter->msix_entries)
> +               ew32(EIAC_82574, 0);
>         e1e_flush();
>         synchronize_irq(adapter->pdev->irq);
>  }
> @@ -1302,7 +1576,12 @@ static void e1000_irq_enable(struct e1000_adapter *adapter)
>  {
>         struct e1000_hw *hw = &adapter->hw;
> 
> -       ew32(IMS, IMS_ENABLE_MASK);
> +       if (adapter->msix_entries) {
> +               ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574);
> +               ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER | E1000_IMS_LSC);
> +       } else {
> +               ew32(IMS, IMS_ENABLE_MASK);
> +       }
>         e1e_flush();
>  }
> 
> @@ -1552,9 +1831,8 @@ void e1000e_free_rx_resources(struct e1000_adapter *adapter)
>   *      traffic pattern.  Constants in this function were computed
>   *      based on theoretical maximum wire speed and thresholds were set based
>   *      on testing data as well as attempting to minimize response time
> - *      while increasing bulk throughput.
> - *      this functionality is controlled by the InterruptThrottleRate module
> - *      parameter (see e1000_param.c)
> + *      while increasing bulk throughput.  This functionality is controlled
> + *      by the InterruptThrottleRate module parameter.
>   **/
>  static unsigned int e1000_update_itr(struct e1000_adapter *adapter,
>                                      u16 itr_setting, int packets,
> @@ -1662,11 +1940,37 @@ set_itr_now:
>                              min(adapter->itr + (new_itr >> 2), new_itr) :
>                              new_itr;
>                 adapter->itr = new_itr;
> -               ew32(ITR, 1000000000 / (new_itr * 256));
> +               adapter->rx_ring->itr_val = new_itr;
> +               if (adapter->msix_entries)
> +                       adapter->rx_ring->set_itr = 1;
> +               else
> +                       ew32(ITR, 1000000000 / (new_itr * 256));
>         }
>  }
> 
>  /**
> + * e1000_alloc_queues - Allocate memory for all rings
> + * @adapter: board private structure to initialize
> + **/
> +static int __devinit e1000_alloc_queues(struct e1000_adapter *adapter)
> +{
> +       adapter->tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
> +       if (!adapter->tx_ring)
> +               goto err;
> +
> +       adapter->rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
> +       if (!adapter->rx_ring)
> +               goto err;
> +
> +       return 0;
> +err:
> +       e_err("Unable to allocate memory for queues\n");
> +       kfree(adapter->rx_ring);
> +       kfree(adapter->tx_ring);
> +       return -ENOMEM;
> +}
> +
> +/**
>   * e1000_clean - NAPI Rx polling callback
>   * @napi: struct associated with this polling callback
>   * @budget: amount of packets driver is allowed to process this poll
> @@ -1674,12 +1978,17 @@ set_itr_now:
>  static int e1000_clean(struct napi_struct *napi, int budget)
>  {
>         struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi);
> +       struct e1000_hw *hw = &adapter->hw;
>         struct net_device *poll_dev = adapter->netdev;
>         int tx_cleaned = 0, work_done = 0;
> 
>         /* Must NOT use netdev_priv macro here. */
>         adapter = poll_dev->priv;
> 
> +       if (adapter->msix_entries &&
> +           !(adapter->rx_ring->ims_val & adapter->tx_ring->ims_val))
> +               goto clean_rx;
> +
>         /*
>          * e1000_clean is called per-cpu.  This lock protects
>          * tx_ring from being cleaned by multiple cpus
> @@ -1691,6 +2000,7 @@ static int e1000_clean(struct napi_struct *napi, int budget)
>                 spin_unlock(&adapter->tx_queue_lock);
>         }
> 
> +clean_rx:
>         adapter->clean_rx(adapter, &work_done, budget);
> 
>         if (tx_cleaned)
> @@ -1701,7 +2011,10 @@ static int e1000_clean(struct napi_struct *napi, int budget)
>                 if (adapter->itr_setting & 3)
>                         e1000_set_itr(adapter);
>                 netif_rx_complete(poll_dev, napi);
> -               e1000_irq_enable(adapter);
> +               if (adapter->msix_entries)
> +                       ew32(IMS, adapter->rx_ring->ims_val);
> +               else
> +                       e1000_irq_enable(adapter);
>         }
> 
>         return work_done;
> @@ -2497,6 +2810,8 @@ int e1000e_up(struct e1000_adapter *adapter)
>         clear_bit(__E1000_DOWN, &adapter->state);
> 
>         napi_enable(&adapter->napi);
> +       if (adapter->msix_entries)
> +               e1000_configure_msix(adapter);
>         e1000_irq_enable(adapter);
> 
>         /* fire a link change interrupt to start the watchdog */
> @@ -2580,13 +2895,10 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter)
>         adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
>         adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
> 
> -       adapter->tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
> -       if (!adapter->tx_ring)
> -               goto err;
> +       e1000e_set_interrupt_capability(adapter);
> 
> -       adapter->rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
> -       if (!adapter->rx_ring)
> -               goto err;
> +       if (e1000_alloc_queues(adapter))
> +               return -ENOMEM;
> 
>         spin_lock_init(&adapter->tx_queue_lock);
> 
> @@ -2597,12 +2909,6 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter)
> 
>         set_bit(__E1000_DOWN, &adapter->state);
>         return 0;
> -
> -err:
> -       e_err("Unable to allocate memory for queues\n");
> -       kfree(adapter->rx_ring);
> -       kfree(adapter->tx_ring);
> -       return -ENOMEM;
>  }
> 
>  /**
> @@ -2644,6 +2950,7 @@ static int e1000_test_msi_interrupt(struct e1000_adapter *adapter)
> 
>         /* free the real vector and request a test handler */
>         e1000_free_irq(adapter);
> +       e1000e_reset_interrupt_capability(adapter);
> 
>         /* Assume that the test fails, if it succeeds then the test
>          * MSI irq handler will unset this flag */
> @@ -2674,6 +2981,7 @@ static int e1000_test_msi_interrupt(struct e1000_adapter *adapter)
>         rmb();
> 
>         if (adapter->flags & FLAG_MSI_TEST_FAILED) {
> +               adapter->int_mode = E1000E_INT_MODE_LEGACY;
>                 err = -EIO;
>                 e_info("MSI interrupt test failed!\n");
>         }
> @@ -2687,7 +2995,7 @@ static int e1000_test_msi_interrupt(struct e1000_adapter *adapter)
>         /* okay so the test worked, restore settings */
>         e_dbg("%s: MSI interrupt test succeeded!\n", netdev->name);
>  msi_test_failed:
> -       /* restore the original vector, even if it failed */
> +       e1000e_set_interrupt_capability(adapter);
>         e1000_request_irq(adapter);
>         return err;
>  }
> @@ -2797,7 +3105,7 @@ static int e1000_open(struct net_device *netdev)
>          * ignore e1000e MSI messages, which means we need to test our MSI
>          * interrupt now
>          */
> -       {
> +       if (adapter->int_mode != E1000E_INT_MODE_LEGACY) {
>                 err = e1000_test_msi(adapter);
>                 if (err) {
>                         e_err("Interrupt allocation failed\n");
> @@ -2989,7 +3297,8 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
> 
>         adapter->stats.algnerrc += er32(ALGNERRC);
>         adapter->stats.rxerrc += er32(RXERRC);
> -       adapter->stats.tncrs += er32(TNCRS);
> +       if (hw->mac.type != e1000_82574)
> +               adapter->stats.tncrs += er32(TNCRS);
>         adapter->stats.cexterr += er32(CEXTERR);
>         adapter->stats.tsctc += er32(TSCTC);
>         adapter->stats.tsctfc += er32(TSCTFC);
> @@ -3337,7 +3646,10 @@ link_up:
>         }
> 
>         /* Cause software interrupt to ensure Rx ring is cleaned */
> -       ew32(ICS, E1000_ICS_RXDMT0);
> +       if (adapter->msix_entries)
> +               ew32(ICS, adapter->rx_ring->ims_val);
> +       else
> +               ew32(ICS, E1000_ICS_RXDMT0);
> 
>         /* Force detection of hung controller every watchdog period */
>         adapter->detect_tx_hung = 1;
> @@ -4054,6 +4366,7 @@ static int e1000_suspend(struct pci_dev *pdev, pm_message_t state)
>                 e1000e_down(adapter);
>                 e1000_free_irq(adapter);
>         }
> +       e1000e_reset_interrupt_capability(adapter);
> 
>         retval = pci_save_state(pdev);
>         if (retval)
> @@ -4180,6 +4493,7 @@ static int e1000_resume(struct pci_dev *pdev)
>         pci_enable_wake(pdev, PCI_D3hot, 0);
>         pci_enable_wake(pdev, PCI_D3cold, 0);
> 
> +       e1000e_set_interrupt_capability(adapter);
>         if (netif_running(netdev)) {
>                 err = e1000_request_irq(adapter);
>                 if (err)
> @@ -4489,6 +4803,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
> 
>         adapter->bd_number = cards_found++;
> 
> +       e1000e_check_options(adapter);
> +
>         /* setup adapter struct */
>         err = e1000_sw_init(adapter);
>         if (err)
> @@ -4595,8 +4911,6 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
>         INIT_WORK(&adapter->reset_task, e1000_reset_task);
>         INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task);
> 
> -       e1000e_check_options(adapter);
> -
>         /* Initialize link parameters. User can change them with ethtool */
>         adapter->hw.mac.autoneg = 1;
>         adapter->fc_autoneg = 1;
> @@ -4726,6 +5040,7 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
>         if (!e1000_check_reset_block(&adapter->hw))
>                 e1000_phy_hw_reset(&adapter->hw);
> 
> +       e1000e_reset_interrupt_capability(adapter);
>         kfree(adapter->tx_ring);
>         kfree(adapter->rx_ring);
> 
> @@ -4767,6 +5082,8 @@ static struct pci_device_id e1000_pci_tbl[] = {
>         { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E_IAMT), board_82573 },
>         { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573L), board_82573 },
> 
> +       { PCI_VDEVICE(INTEL, E1000_DEV_ID_82574L), board_82574 },
> +
>         { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_DPT),
>           board_80003es2lan },
>         { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_SPT),
> diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c
> index ed912e0..f46db6c 100644
> --- a/drivers/net/e1000e/param.c
> +++ b/drivers/net/e1000e/param.c
> @@ -114,6 +114,15 @@ E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate");
>  #define DEFAULT_ITR 3
>  #define MAX_ITR 100000
>  #define MIN_ITR 100
> +/* IntMode (Interrupt Mode)
> + *
> + * Valid Range: 0 - 2
> + *
> + * Default Value: 2 (MSI-X)
> + */
> +E1000_PARAM(IntMode, "Interrupt Mode");
> +#define MAX_INTMODE    2
> +#define MIN_INTMODE    0
> 
>  /*
>   * Enable Smart Power Down of the PHY
> @@ -352,6 +361,24 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
>                         adapter->itr = 20000;
>                 }
>         }
> +       { /* Interrupt Mode */
> +               struct e1000_option opt = {
> +                       .type = range_option,
> +                       .name = "Interrupt Mode",
> +                       .err  = "defaulting to 2 (MSI-X)",
> +                       .def  = E1000E_INT_MODE_MSIX,
> +                       .arg  = { .r = { .min = MIN_INTMODE,
> +                                        .max = MAX_INTMODE } }
> +               };
> +
> +               if (num_IntMode > bd) {
> +                       unsigned int int_mode = IntMode[bd];
> +                       e1000_validate_option(&int_mode, &opt, adapter);
> +                       adapter->int_mode = int_mode;
> +               } else {
> +                       adapter->int_mode = opt.def;
> +               }
> +       }
>         { /* Smart Power Down */
>                 const struct e1000_option opt = {
>                         .type = enable_option,
> diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c
> index 16724f8..6cd333a 100644
> --- a/drivers/net/e1000e/phy.c
> +++ b/drivers/net/e1000e/phy.c
> @@ -476,7 +476,9 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
>         if (ret_val)
>                 return ret_val;
> 
> -       if ((phy->type == e1000_phy_m88) && (phy->revision < 4)) {
> +       if ((phy->type == e1000_phy_m88) &&
> +           (phy->revision < E1000_REVISION_4) &&
> +           (phy->id != BME1000_E_PHY_ID_R2)) {
>                 /*
>                  * Force TX_CLK in the Extended PHY Specific Control Register
>                  * to 25MHz clock.
> @@ -504,6 +506,18 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
>                         return ret_val;
>         }
> 
> +       if ((phy->type == e1000_phy_bm) && (phy->id == BME1000_E_PHY_ID_R2)) {
> +               /* Set PHY page 0, register 29 to 0x0003 */
> +               ret_val = e1e_wphy(hw, 29, 0x0003);
> +               if (ret_val)
> +                       return ret_val;
> +
> +               /* Set PHY page 0, register 30 to 0x0000 */
> +               ret_val = e1e_wphy(hw, 30, 0x0000);
> +               if (ret_val)
> +                       return ret_val;
> +       }
> +
>         /* Commit the changes. */
>         ret_val = e1000e_commit_phy(hw);
>         if (ret_val)
> @@ -2054,6 +2068,99 @@ out:
>  }
> 
>  /**
> + *  e1000e_read_phy_reg_bm2 - Read BM 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.
> + **/
> +s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data)
> +{
> +       s32 ret_val;
> +       u16 page = (u16)(offset >> IGP_PAGE_SHIFT);
> +
> +       /* Page 800 works differently than the rest so it has its own func */
> +       if (page == BM_WUC_PAGE) {
> +               ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data,
> +                                                        true);
> +               return ret_val;
> +       }
> +
> +       ret_val = hw->phy.ops.acquire_phy(hw);
> +       if (ret_val)
> +               return ret_val;
> +
> +       hw->phy.addr = 1;
> +
> +       if (offset > MAX_PHY_MULTI_PAGE_REG) {
> +
> +               /* Page is shifted left, PHY expects (page x 32) */
> +               ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
> +                                                   page);
> +
> +               if (ret_val) {
> +                       hw->phy.ops.release_phy(hw);
> +                       return ret_val;
> +               }
> +       }
> +
> +       ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
> +                                          data);
> +       hw->phy.ops.release_phy(hw);
> +
> +       return ret_val;
> +}
> +
> +/**
> + *  e1000e_write_phy_reg_bm2 - Write BM PHY register
> + *  @hw: pointer to the HW structure
> + *  @offset: register offset to write to
> + *  @data: data to write at register offset
> + *
> + *  Acquires semaphore, if necessary, then writes the data to PHY register
> + *  at the offset.  Release any acquired semaphores before exiting.
> + **/
> +s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data)
> +{
> +       s32 ret_val;
> +       u16 page = (u16)(offset >> IGP_PAGE_SHIFT);
> +
> +       /* Page 800 works differently than the rest so it has its own func */
> +       if (page == BM_WUC_PAGE) {
> +               ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data,
> +                                                        false);
> +               return ret_val;
> +       }
> +
> +       ret_val = hw->phy.ops.acquire_phy(hw);
> +       if (ret_val)
> +               return ret_val;
> +
> +       hw->phy.addr = 1;
> +
> +       if (offset > MAX_PHY_MULTI_PAGE_REG) {
> +               /* Page is shifted left, PHY expects (page x 32) */
> +               ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
> +                                                   page);
> +
> +               if (ret_val) {
> +                       hw->phy.ops.release_phy(hw);
> +                       return ret_val;
> +               }
> +       }
> +
> +       ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
> +                                           data);
> +
> +       hw->phy.ops.release_phy(hw);
> +
> +       return ret_val;
> +}
> +
> +/**
>   *  e1000_access_phy_wakeup_reg_bm - Read BM PHY wakeup register
>   *  @hw: pointer to the HW structure
>   *  @offset: register offset to be read or written
> 
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [UPDATED PATCH] e1000e: add support for new 82574L part
  2008-08-13 15:29 ` Arthur Jones
@ 2008-08-13 20:53   ` Jeff Kirsher
  0 siblings, 0 replies; 3+ messages in thread
From: Jeff Kirsher @ 2008-08-13 20:53 UTC (permalink / raw)
  To: Arthur Jones
  Cc: jeff@garzik.org, netdev@vger.kernel.org,
	akpm@linux-foundation.org, Bruce Allan

On Wed, Aug 13, 2008 at 8:29 AM, Arthur Jones <ajones@riverbed.com> wrote:
> Hi Jeff,  This patch doesn't apply for me as
> it seems to be tab -> space mangled...
>
> Arthur
>

I apologize, working on a resolution so that the patch does not get
munged during transport.

-- 
Cheers,
Jeff

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

end of thread, other threads:[~2008-08-13 20:53 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-08-13  7:30 [UPDATED PATCH] e1000e: add support for new 82574L part Jeff Kirsher
2008-08-13 15:29 ` Arthur Jones
2008-08-13 20:53   ` Jeff Kirsher

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