[kernel] r13856 - in dists/lenny/linux-2.6/debian: . patches/features/all patches/series

Dann Frazier dannf at alioth.debian.org
Tue Jun 30 05:03:41 UTC 2009


Author: dannf
Date: Tue Jun 30 05:03:37 2009
New Revision: 13856

Log:
* e1000e: add support for 82574L controllers (closes: #534519)

Added:
   dists/lenny/linux-2.6/debian/patches/features/all/e1000e-add-support-for-82574l.patch
   dists/lenny/linux-2.6/debian/patches/features/all/e1000e-test-for-unusable-MSI-support.patch
Modified:
   dists/lenny/linux-2.6/debian/changelog
   dists/lenny/linux-2.6/debian/patches/series/18

Modified: dists/lenny/linux-2.6/debian/changelog
==============================================================================
--- dists/lenny/linux-2.6/debian/changelog	Mon Jun 29 18:04:19 2009	(r13855)
+++ dists/lenny/linux-2.6/debian/changelog	Tue Jun 30 05:03:37 2009	(r13856)
@@ -12,6 +12,9 @@
   * MIPS: IP22/28: Switch over to RTC class driver
   * [mips/r4k-ip22] Build in RTC_DRV_DS1286. (Closes: #533895)
 
+  [ dann frazier ]
+  * e1000e: add support for 82574L controllers (closes: #534519)
+
  -- maximilian attems <maks at debian.org>  Wed, 10 Jun 2009 15:34:04 +0200
 
 linux-2.6 (2.6.26-17) stable; urgency=high

Added: dists/lenny/linux-2.6/debian/patches/features/all/e1000e-add-support-for-82574l.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/lenny/linux-2.6/debian/patches/features/all/e1000e-add-support-for-82574l.patch	Tue Jun 30 05:03:37 2009	(r13856)
@@ -0,0 +1,1511 @@
+commit 4662e82b2cb41c60826e50474dd86dd5c6372b0c
+Author: Bruce Allan <bruce.w.allan at intel.com>
+Date:   Tue Aug 26 18:37:06 2008 -0700
+
+    e1000e: add support for new 82574L part
+    
+    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 at intel.com>
+    Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher at intel.com>
+    Signed-off-by: Jeff Garzik <jgarzik at redhat.com>
+
+Backported to Debian's 2.6.26 by dann frazier <dannf at debian.org>
+
+diff -urpN linux-source-2.6.26.orig/drivers/net/e1000e/82571.c linux-source-2.6.26/drivers/net/e1000e/82571.c
+--- linux-source-2.6.26.orig/drivers/net/e1000e/82571.c	2008-07-13 15:51:29.000000000 -0600
++++ linux-source-2.6.26/drivers/net/e1000e/82571.c	2009-06-19 17:25:39.000000000 -0600
+@@ -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(
+ 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(s
+ 	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(s
+ 		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(s
+ 
+ 	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(s
+ 		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(stru
+ 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
+ 	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(struc
+ 	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 
+ 
+ 	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 e
+ 	 * 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 e
+ 	 * 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 e1
+ 	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_825
+ 	}
+ 
+ 	/* 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 *
+ 	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 *
+ }
+ 
+ /**
++ *  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
+ 	 * 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
+ 
+ 	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
+ 		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(s
+ }
+ 
+ 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_p
+ 	.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 -urpN linux-source-2.6.26.orig/drivers/net/e1000e/defines.h linux-source-2.6.26/drivers/net/e1000e/defines.h
+--- linux-source-2.6.26.orig/drivers/net/e1000e/defines.h	2009-06-19 17:25:12.000000000 -0600
++++ linux-source-2.6.26/drivers/net/e1000e/defines.h	2009-06-19 17:25:39.000000000 -0600
+@@ -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 -urpN linux-source-2.6.26.orig/drivers/net/e1000e/e1000.h linux-source-2.6.26/drivers/net/e1000e/e1000.h
+--- linux-source-2.6.26.orig/drivers/net/e1000e/e1000.h	2009-06-19 17:25:12.000000000 -0600
++++ linux-source-2.6.26/drivers/net/e1000e/e1000.h	2009-06-19 17:25:39.000000000 -0600
+@@ -61,6 +61,11 @@ struct e1000_info;
+ 	ndev_printk(KERN_NOTICE , netdev, 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
+@@ -94,6 +99,7 @@ enum e1000_boards {
+ 	board_82571,
+ 	board_82572,
+ 	board_82573,
++	board_82574,
+ 	board_80003es2lan,
+ 	board_ich8lan,
+ 	board_ich9lan,
+@@ -145,6 +151,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;
+@@ -273,6 +285,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;
+@@ -305,6 +320,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)
+@@ -363,6 +379,8 @@ extern int e1000e_setup_tx_resources(str
+ 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;
+ 
+@@ -371,6 +389,7 @@ extern char *e1000e_get_hw_dev_name(stru
+ 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_es2_info;
+@@ -449,6 +468,8 @@ extern enum e1000_phy_type e1000e_get_ph
+ 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);
+@@ -519,7 +540,12 @@ static inline s32 e1000_get_phy_info(str
+ 	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 -urpN linux-source-2.6.26.orig/drivers/net/e1000e/es2lan.c linux-source-2.6.26/drivers/net/e1000e/es2lan.c
+--- linux-source-2.6.26.orig/drivers/net/e1000e/es2lan.c	2008-07-13 15:51:29.000000000 -0600
++++ linux-source-2.6.26/drivers/net/e1000e/es2lan.c	2009-06-19 17:25:39.000000000 -0600
+@@ -1247,7 +1247,7 @@ static void e1000_clear_hw_cntrs_80003es
+ }
+ 
+ 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 -urpN linux-source-2.6.26.orig/drivers/net/e1000e/ethtool.c linux-source-2.6.26/drivers/net/e1000e/ethtool.c
+--- linux-source-2.6.26.orig/drivers/net/e1000e/ethtool.c	2008-07-13 15:51:29.000000000 -0600
++++ linux-source-2.6.26/drivers/net/e1000e/ethtool.c	2009-06-19 17:25:39.000000000 -0600
+@@ -571,6 +571,7 @@ static int e1000_set_eeprom(struct net_d
+ 	 * 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);
+ 
+@@ -785,6 +786,7 @@ static int e1000_reg_test(struct e1000_a
+ 		toggle = 0x7FFFF3FF;
+ 		break;
+ 	case e1000_82573:
++	case e1000_82574:
+ 	case e1000_ich8lan:
+ 	case e1000_ich9lan:
+ 		toggle = 0x7FFFF033;
+@@ -890,10 +892,18 @@ static int e1000_intr_test(struct e1000_
+ 	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)) {
+@@ -901,7 +911,8 @@ static int e1000_intr_test(struct e1000_
+ 	} else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED,
+ 		 netdev->name, netdev)) {
+ 		*data = 1;
+-		return -1;
++		ret_val = -1;
++		goto out;
+ 	}
+ 	ndev_info(netdev, "testing %s interrupt\n",
+ 		  (shared_int ? "shared" : "unshared"));
+@@ -981,7 +992,14 @@ static int e1000_intr_test(struct e1000_
+ 	/* 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)
+@@ -1763,11 +1781,13 @@ static void e1000_led_blink_callback(uns
+ 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 =
+@@ -1777,16 +1797,16 @@ static int e1000_phys_id(struct net_devi
+ 		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 -urpN linux-source-2.6.26.orig/drivers/net/e1000e/hw.h linux-source-2.6.26/drivers/net/e1000e/hw.h
+--- linux-source-2.6.26.orig/drivers/net/e1000e/hw.h	2008-07-13 15:51:29.000000000 -0600
++++ linux-source-2.6.26/drivers/net/e1000e/hw.h	2009-06-19 17:25:39.000000000 -0600
+@@ -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
+@@ -357,12 +362,15 @@ enum e1e_registers {
+ #define E1000_DEV_ID_ICH10_R_BM_LF		0x10CD
+ #define E1000_DEV_ID_ICH10_R_BM_V		0x10CE
+ 
++#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,
+@@ -696,8 +704,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 -urpN linux-source-2.6.26.orig/drivers/net/e1000e/ich8lan.c linux-source-2.6.26/drivers/net/e1000e/ich8lan.c
+--- linux-source-2.6.26.orig/drivers/net/e1000e/ich8lan.c	2008-07-13 15:51:29.000000000 -0600
++++ linux-source-2.6.26/drivers/net/e1000e/ich8lan.c	2009-06-19 17:25:39.000000000 -0600
+@@ -417,6 +417,22 @@ static void e1000_release_swflag_ich8lan
+ }
+ 
+ /**
++ *  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
+  *
+@@ -2282,7 +2298,7 @@ static void e1000_clear_hw_cntrs_ich8lan
+ }
+ 
+ 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 -urpN linux-source-2.6.26.orig/drivers/net/e1000e/lib.c linux-source-2.6.26/drivers/net/e1000e/lib.c
+--- linux-source-2.6.26.orig/drivers/net/e1000e/lib.c	2008-07-13 15:51:29.000000000 -0600
++++ linux-source-2.6.26/drivers/net/e1000e/lib.c	2009-06-19 17:25:39.000000000 -0600
+@@ -2222,17 +2222,18 @@ static s32 e1000_mng_enable_host_if(stru
+ }
+ 
+ /**
+- *  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 -urpN linux-source-2.6.26.orig/drivers/net/e1000e/param.c linux-source-2.6.26/drivers/net/e1000e/param.c
+--- linux-source-2.6.26.orig/drivers/net/e1000e/param.c	2008-07-13 15:51:29.000000000 -0600
++++ linux-source-2.6.26/drivers/net/e1000e/param.c	2009-06-19 17:25:39.000000000 -0600
+@@ -113,6 +113,15 @@ E1000_PARAM(InterruptThrottleRate, "Inte
+ #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
+@@ -346,6 +355,24 @@ void __devinit e1000e_check_options(stru
+ 			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 -urpN linux-source-2.6.26.orig/drivers/net/e1000e/phy.c linux-source-2.6.26/drivers/net/e1000e/phy.c
+--- linux-source-2.6.26.orig/drivers/net/e1000e/phy.c	2008-07-13 15:51:29.000000000 -0600
++++ linux-source-2.6.26/drivers/net/e1000e/phy.c	2009-06-19 17:25:39.000000000 -0600
+@@ -476,7 +476,9 @@ s32 e1000e_copper_link_setup_m88(struct 
+ 	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 
+ 			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)
+@@ -1969,6 +1983,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
+--- linux-source-2.6.26.orig/drivers/net/e1000e/netdev.c	2009-06-19 17:25:12.000000000 -0600
++++ linux-source-2.6.26/drivers/net/e1000e/netdev.c	2009-06-19 17:28:47.000000000 -0600
+@@ -55,6 +55,7 @@ static const struct e1000_info *e1000_in
+ 	[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,
+@@ -1179,8 +1180,8 @@ static irqreturn_t e1000_intr(int irq, v
+ 	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 */
+ 
+@@ -1236,6 +1237,265 @@ static irqreturn_t e1000_intr(int irq, v
+ 	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;
++	struct net_device *netdev = adapter->netdev;
++
++	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 */
++			ndev_err(netdev,
++				 "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;
++			ndev_err(netdev,
++				 "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
+  *
+@@ -1245,29 +1505,33 @@ static irqreturn_t e1000_intr(int irq, v
+ 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;
+-		}
++		/* 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)
+ 		ndev_err(netdev,
+ 			 "Unable to allocate interrupt, Error: %d\n", err);
+-	}
+ 
+ 	return err;
+ }
+@@ -1276,11 +1540,21 @@ static void e1000_free_irq(struct e1000_
+ {
+ 	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 +1565,8 @@ static void e1000_irq_disable(struct e10
+ 	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 +1578,12 @@ static void e1000_irq_enable(struct e100
+ {
+ 	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();
+ }
+ 
+@@ -1554,9 +1835,8 @@ void e1000e_free_rx_resources(struct e10
+  *      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,
+@@ -1664,11 +1944,39 @@ 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)
++{
++	struct net_device *netdev = adapter->netdev;
++
++	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:
++	ndev_err(netdev, "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
+@@ -1676,12 +1984,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
+@@ -1693,6 +2006,7 @@ static int e1000_clean(struct napi_struc
+ 		spin_unlock(&adapter->tx_queue_lock);
+ 	}
+ 
++clean_rx:
+ 	adapter->clean_rx(adapter, &work_done, budget);
+ 
+ 	if (tx_cleaned)
+@@ -1703,7 +2017,10 @@ static int e1000_clean(struct napi_struc
+ 		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;
+@@ -2499,6 +2816,8 @@ int e1000e_up(struct e1000_adapter *adap
+ 	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 */
+@@ -2582,13 +2901,10 @@ static int __devinit e1000_sw_init(struc
+ 	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);
+ 
+@@ -2599,12 +2915,6 @@ static int __devinit e1000_sw_init(struc
+ 
+ 	set_bit(__E1000_DOWN, &adapter->state);
+ 	return 0;
+-
+-err:
+-	ndev_err(netdev, "Unable to allocate memory for queues\n");
+-	kfree(adapter->rx_ring);
+-	kfree(adapter->tx_ring);
+-	return -ENOMEM;
+ }
+ 
+ /**
+@@ -2646,6 +2956,7 @@ static int e1000_test_msi_interrupt(stru
+ 
+ 	/* 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 */
+@@ -2676,6 +2987,7 @@ static int e1000_test_msi_interrupt(stru
+ 	rmb();
+ 
+ 	if (adapter->flags & FLAG_MSI_TEST_FAILED) {
++		adapter->int_mode = E1000E_INT_MODE_LEGACY;
+ 		err = -EIO;
+ 		ndev_info(netdev, "MSI interrupt test failed!\n");
+ 	}
+@@ -2689,7 +3001,7 @@ static int e1000_test_msi_interrupt(stru
+ 	/* okay so the test worked, restore settings */
+ 	ndev_dbg(netdev, "%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;
+ }
+@@ -2802,7 +3114,7 @@ static int e1000_open(struct net_device 
+ 	 * 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) {
+ 			ndev_err(netdev, "Interrupt allocation failed\n");
+@@ -2993,7 +3305,8 @@ void e1000e_update_stats(struct e1000_ad
+ 
+ 	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);
+@@ -3325,7 +3638,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;
+@@ -4043,6 +4359,7 @@ static int e1000_suspend(struct pci_dev 
+ 		e1000e_down(adapter);
+ 		e1000_free_irq(adapter);
+ 	}
++	e1000e_reset_interrupt_capability(adapter);
+ 
+ 	retval = pci_save_state(pdev);
+ 	if (retval)
+@@ -4168,6 +4485,7 @@ static int e1000_resume(struct pci_dev *
+ 	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)
+@@ -4456,6 +4774,8 @@ static int __devinit e1000_probe(struct 
+ 
+ 	adapter->bd_number = cards_found++;
+ 
++	e1000e_check_options(adapter);
++
+ 	/* setup adapter struct */
+ 	err = e1000_sw_init(adapter);
+ 	if (err)
+@@ -4557,8 +4877,6 @@ static int __devinit e1000_probe(struct 
+ 	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;
+@@ -4688,6 +5006,7 @@ static void __devexit e1000_remove(struc
+ 	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);
+ 
+@@ -4728,6 +5047,8 @@ static struct pci_device_id e1000_pci_tb
+ 	{ 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),

Added: dists/lenny/linux-2.6/debian/patches/features/all/e1000e-test-for-unusable-MSI-support.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/lenny/linux-2.6/debian/patches/features/all/e1000e-test-for-unusable-MSI-support.patch	Tue Jun 30 05:03:37 2009	(r13856)
@@ -0,0 +1,250 @@
+commit f8d59f7826aa73c5e7682fbed6db38020635d466
+Author: Bruce Allan <bruce.w.allan at intel.com>
+Date:   Fri Aug 8 18:36:11 2008 -0700
+
+    e1000e: test for unusable MSI support
+    
+    Some systems do not like 82571/2 use of 16-bit MSI messages and some
+    other systems claim to support MSI, but neither really works.  Setup a
+    test MSI handler to detect whether or not MSI is working properly, and
+    if not, fallback to legacy INTx interrupts.
+    
+    Signed-off-by: Bruce Allan <bruce.w.allan at intel.com>
+    Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher at intel.com>
+    Signed-off-by: Jeff Garzik <jgarzik at redhat.com>
+
+Backported to Debian's 2.6.26 by dann frazier <dannf at debian.org>
+
+diff -urpN linux-source-2.6.26.orig/drivers/net/e1000e/defines.h linux-source-2.6.26/drivers/net/e1000e/defines.h
+--- linux-source-2.6.26.orig/drivers/net/e1000e/defines.h	2008-07-13 15:51:29.000000000 -0600
++++ linux-source-2.6.26/drivers/net/e1000e/defines.h	2009-06-19 16:54:12.000000000 -0600
+@@ -389,7 +389,7 @@
+ 
+ /* Interrupt Cause Set */
+ #define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
+-#define E1000_ICS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
++#define E1000_ICS_RXSEQ     E1000_ICR_RXSEQ     /* Rx sequence error */
+ #define E1000_ICS_RXDMT0    E1000_ICR_RXDMT0    /* Rx desc min. threshold */
+ 
+ /* Transmit Descriptor Control */
+diff -urpN linux-source-2.6.26.orig/drivers/net/e1000e/e1000.h linux-source-2.6.26/drivers/net/e1000e/e1000.h
+--- linux-source-2.6.26.orig/drivers/net/e1000e/e1000.h	2008-07-13 15:51:29.000000000 -0600
++++ linux-source-2.6.26/drivers/net/e1000e/e1000.h	2009-06-19 16:54:12.000000000 -0600
+@@ -325,6 +325,7 @@ struct e1000_info {
+ #define FLAG_RX_CSUM_ENABLED              (1 << 28)
+ #define FLAG_TSO_FORCE                    (1 << 29)
+ #define FLAG_RX_RESTART_NOW               (1 << 30)
++#define FLAG_MSI_TEST_FAILED              (1 << 31)
+ 
+ #define E1000_RX_DESC_PS(R, i)	    \
+ 	(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
+--- linux-source-2.6.26.orig/drivers/net/e1000e/netdev.c	2008-07-13 15:51:29.000000000 -0600
++++ linux-source-2.6.26/drivers/net/e1000e/netdev.c	2009-06-19 17:21:48.000000000 -0600
+@@ -1236,28 +1236,37 @@ static irqreturn_t e1000_intr(int irq, v
+ 	return IRQ_HANDLED;
+ }
+ 
++/**
++ * e1000_request_irq - initialize interrupts
++ *
++ * Attempts to configure interrupts using the best available
++ * capabilities of the hardware and kernel.
++ **/
+ static int e1000_request_irq(struct e1000_adapter *adapter)
+ {
+ 	struct net_device *netdev = adapter->netdev;
+-	irq_handler_t handler = e1000_intr;
+ 	int irq_flags = IRQF_SHARED;
+ 	int err;
+ 
+-	if (!pci_enable_msi(adapter->pdev)) {
+-		adapter->flags |= FLAG_MSI_ENABLED;
+-		handler = e1000_intr_msi;
+-		irq_flags = 0;
++	if (!(adapter->flags & FLAG_MSI_TEST_FAILED)) {
++		err = pci_enable_msi(adapter->pdev);
++		if (!err) {
++			adapter->flags |= FLAG_MSI_ENABLED;
++			irq_flags = 0;
++		}
+ 	}
+ 
+-	err = request_irq(adapter->pdev->irq, handler, irq_flags, netdev->name,
+-			  netdev);
++	err = request_irq(adapter->pdev->irq,
++			  ((adapter->flags & FLAG_MSI_ENABLED) ?
++				&e1000_intr_msi : &e1000_intr),
++			  irq_flags, netdev->name, netdev);
+ 	if (err) {
+-		ndev_err(netdev,
+-		       "Unable to allocate %s interrupt (return: %d)\n",
+-			adapter->flags & FLAG_MSI_ENABLED ? "MSI":"INTx",
+-			err);
+-		if (adapter->flags & FLAG_MSI_ENABLED)
++		if (adapter->flags & FLAG_MSI_ENABLED) {
+ 			pci_disable_msi(adapter->pdev);
++			adapter->flags &= ~FLAG_MSI_ENABLED;
++		}
++		ndev_err(netdev,
++			 "Unable to allocate interrupt, Error: %d\n", err);
+ 	}
+ 
+ 	return err;
+@@ -2599,6 +2608,137 @@ err:
+ }
+ 
+ /**
++ * e1000_intr_msi_test - Interrupt Handler
++ * @irq: interrupt number
++ * @data: pointer to a network interface device structure
++ **/
++static irqreturn_t e1000_intr_msi_test(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);
++
++	ndev_dbg(netdev, "%s: icr is %08X\n", netdev->name, icr);
++	if (icr & E1000_ICR_RXSEQ) {
++		adapter->flags &= ~FLAG_MSI_TEST_FAILED;
++		wmb();
++	}
++
++	return IRQ_HANDLED;
++}
++
++/**
++ * e1000_test_msi_interrupt - Returns 0 for successful test
++ * @adapter: board private struct
++ *
++ * code flow taken from tg3.c
++ **/
++static int e1000_test_msi_interrupt(struct e1000_adapter *adapter)
++{
++	struct net_device *netdev = adapter->netdev;
++	struct e1000_hw *hw = &adapter->hw;
++	int err;
++
++	/* poll_enable hasn't been called yet, so don't need disable */
++	/* clear any pending events */
++	er32(ICR);
++
++	/* free the real vector and request a test handler */
++	e1000_free_irq(adapter);
++
++	/* Assume that the test fails, if it succeeds then the test
++	 * MSI irq handler will unset this flag */
++	adapter->flags |= FLAG_MSI_TEST_FAILED;
++
++	err = pci_enable_msi(adapter->pdev);
++	if (err)
++		goto msi_test_failed;
++
++	err = request_irq(adapter->pdev->irq, &e1000_intr_msi_test, 0,
++			  netdev->name, netdev);
++	if (err) {
++		pci_disable_msi(adapter->pdev);
++		goto msi_test_failed;
++	}
++
++	wmb();
++
++	e1000_irq_enable(adapter);
++
++	/* fire an unusual interrupt on the test handler */
++	ew32(ICS, E1000_ICS_RXSEQ);
++	e1e_flush();
++	msleep(50);
++
++	e1000_irq_disable(adapter);
++
++	rmb();
++
++	if (adapter->flags & FLAG_MSI_TEST_FAILED) {
++		err = -EIO;
++		ndev_info(netdev, "MSI interrupt test failed!\n");
++	}
++
++	free_irq(adapter->pdev->irq, netdev);
++	pci_disable_msi(adapter->pdev);
++
++	if (err == -EIO)
++		goto msi_test_failed;
++
++	/* okay so the test worked, restore settings */
++	ndev_dbg(netdev, "%s: MSI interrupt test succeeded!\n", netdev->name);
++msi_test_failed:
++	/* restore the original vector, even if it failed */
++	e1000_request_irq(adapter);
++	return err;
++}
++
++/**
++ * e1000_test_msi - Returns 0 if MSI test succeeds or INTx mode is restored
++ * @adapter: board private struct
++ *
++ * code flow taken from tg3.c, called with e1000 interrupts disabled.
++ **/
++static int e1000_test_msi(struct e1000_adapter *adapter)
++{
++	int err;
++	u16 pci_cmd;
++	struct net_device *netdev = adapter->netdev;
++
++	if (!(adapter->flags & FLAG_MSI_ENABLED))
++		return 0;
++
++	/* disable SERR in case the MSI write causes a master abort */
++	pci_read_config_word(adapter->pdev, PCI_COMMAND, &pci_cmd);
++	pci_write_config_word(adapter->pdev, PCI_COMMAND,
++			      pci_cmd & ~PCI_COMMAND_SERR);
++
++	err = e1000_test_msi_interrupt(adapter);
++
++	/* restore previous setting of command word */
++	pci_write_config_word(adapter->pdev, PCI_COMMAND, pci_cmd);
++
++	/* success ! */
++	if (!err)
++		return 0;
++
++	/* EIO means MSI test failed */
++	if (err != -EIO)
++		return err;
++
++	/* back to INTx mode */
++	ndev_warn(netdev, 
++		  "MSI interrupt test failed, using legacy interrupt.\n");
++
++	e1000_free_irq(adapter);
++
++	err = e1000_request_irq(adapter);
++
++	return err;
++}
++
++/**
+  * e1000_open - Called when a network interface is made active
+  * @netdev: network interface device structure
+  *
+@@ -2657,6 +2797,19 @@ static int e1000_open(struct net_device 
+ 	if (err)
+ 		goto err_req_irq;
+ 
++	/*
++	 * Work around PCIe errata with MSI interrupts causing some chipsets to
++	 * ignore e1000e MSI messages, which means we need to test our MSI
++	 * interrupt now
++	 */
++	{
++		err = e1000_test_msi(adapter);
++		if (err) {
++			ndev_err(netdev, "Interrupt allocation failed\n");
++			goto err_req_irq;
++		}
++	}
++
+ 	/* From here on the code is the same as e1000e_up() */
+ 	clear_bit(__E1000_DOWN, &adapter->state);
+ 

Modified: dists/lenny/linux-2.6/debian/patches/series/18
==============================================================================
--- dists/lenny/linux-2.6/debian/patches/series/18	Mon Jun 29 18:04:19 2009	(r13855)
+++ dists/lenny/linux-2.6/debian/patches/series/18	Tue Jun 30 05:03:37 2009	(r13856)
@@ -1,3 +1,5 @@
 + bugfix/all/rtc-ds1286.patch
 + bugfix/all/rtc-ds1286-include.patch
 + bugfix/mips/rtc-use-platform.patch
++ features/all/e1000e-test-for-unusable-MSI-support.patch
++ features/all/e1000e-add-support-for-82574l.patch



More information about the Kernel-svn-changes mailing list