Skip to contentSkip to conversation

e1000e fails probe

PATCH Pete Zaitcev 3 participants 5 messages May 11, 2010

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

Dear All:

I have a box where e1000e would refuse to probe the onboard interface with the following in dmesg:

e1000e: Intel(R) PRO/1000 Network Driver - 1.0.2-k2
e1000e: Copyright (c) 1999 - 2009 Intel Corporation. e1000e 0000:00:19.0: PCI INT A -> GSI 20 (level, low) -> IRQ 20 e1000e 0000:00:19.0: setting latency timer to 64 e1000e 0000:00:19.0: irq 34 for MSI/MSI-X 0000:00:19.0: 0000:00:19.0: MDI Error
e1000e 0000:00:19.0: PCI INT A disabled
e1000e: probe of 0000:00:19.0 failed with error -2

The "MDI Error" seems to indicate a hardware failure, so I paid it no mind until I noticed that RHEL 5 works. So, I diffed the drivers between Linus' 2.6.34-rc5 and RHEL's 2.6.18-180.el5, with the following minimal patch working for me:

drivers/net/e1000e/ich8lan.c +168 -10
index 8b5e157..b97cd9f 100644
@@ -276,19 +276,21 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
 
 	phy->id = e1000_phy_unknown;
 	ret_val = e1000e_get_phy_id(hw);
-	if (ret_val)
-		goto out;
-	if ((phy->id == 0) || (phy->id == PHY_REVISION_MASK)) {
+/* P3 */ printk("get_phy_id.fast ret %d id %d\n", ret_val, phy->id);
+	if (ret_val || (phy->id == 0) || (phy->id == PHY_REVISION_MASK)) {
 		/*
 		 * In case the PHY needs to be in mdio slow mode (eg. 82577),
 		 * set slow mode and try to get the PHY id again.
 		 */
 		ret_val = e1000_set_mdio_slow_mode_hv(hw);
-		if (ret_val)
-			goto out;
-		ret_val = e1000e_get_phy_id(hw);
-		if (ret_val)
-			goto out;
+		if (ret_val) {
+/* P3 */ printk("failed to set mdio slow mode %d\n", ret_val);
+			phy->id = e1000_phy_unknown;
+		} else {
+			ret_val = e1000e_get_phy_id(hw);
+/* P3 */ printk("get_phy_id.slow ret %d id %d\n", ret_val, phy->id);
+		}
+		ret_val = 0; /* P3 */
 	}
 	phy->type = e1000e_get_phy_type_from_id(phy->id);
 
@@ -307,11 +309,10 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
 		phy->ops.get_info = e1000e_get_phy_info_m88;
 		break;
 	default:
-		ret_val = -E1000_ERR_PHY;
+/* P3 */ printk("not doing anything for phy type %d\n", phy->type);
 		break;
 	}
 
-out:
 	return ret_val;
 }
 
@@ -354,7 +355,10 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
 		msleep(1);
 		ret_val = e1000e_get_phy_id(hw);
 		if (ret_val)
+{
+/* P3 */ printk("get_phy_id for params ret %d id %d\n", ret_val, phy->id);
 			return ret_val;
+}
 	}
 
 	/* Verify phy id */
@@ -777,6 +781,77 @@ static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
 }
 
 /**
+ *  e1000_phy_force_speed_duplex_ich8lan - Force PHY speed & duplex
+ *  @hw: pointer to the HW structure
+ *
+ *  Forces the speed and duplex settings of the PHY.
+ *  This is a function pointer entry point only called by
+ *  PHY setup routines.
+ **/
+static s32 e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+	bool link;
+
+	if (phy->type != e1000_phy_ife) {
+		ret_val = e1000e_phy_force_speed_duplex_igp(hw);
+		return ret_val;
+	}
+
+	ret_val = e1e_rphy(hw, PHY_CONTROL, &data);
+	if (ret_val)
+		return ret_val;
+
+	e1000e_phy_force_speed_duplex_setup(hw, &data);
+
+	ret_val = e1e_wphy(hw, PHY_CONTROL, data);
+	if (ret_val)
+		return ret_val;
+
+	/* Disable MDI-X support for 10/100 */
+	ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data);
+	if (ret_val)
+		return ret_val;
+
+	data &= ~IFE_PMC_AUTO_MDIX;
+	data &= ~IFE_PMC_FORCE_MDIX;
+
+	ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, data);
+	if (ret_val)
+		return ret_val;
+
+	e_dbg("IFE PMC: %X\n", data);
+
+	udelay(1);
+
+	if (phy->autoneg_wait_to_complete) {
+		e_dbg("Waiting for forced speed/duplex link on IFE phy.\n");
+
+		ret_val = e1000e_phy_has_link_generic(hw,
+						     PHY_FORCE_LIMIT,
+						     100000,
+						     &link);
+		if (ret_val)
+			return ret_val;
+
+		if (!link)
+			e_dbg("Link taking longer than expected.\n");
+
+		/* Try once more */
+		ret_val = e1000e_phy_has_link_generic(hw,
+						     PHY_FORCE_LIMIT,
+						     100000,
+						     &link);
+		if (ret_val)
+			return ret_val;
+	}
+
+	return 0;
+}
+
+/**
  *  e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration
  *  @hw:   pointer to the HW structure
  *
@@ -1273,6 +1348,87 @@ out:
 }
 
 /**
+ *  e1000_get_phy_info_ife_ich8lan - Retrieves various IFE PHY states
+ *  @hw: pointer to the HW structure
+ *
+ *  Populates "phy" structure with various feature states.
+ *  This function is only called by other family-specific
+ *  routines.
+ **/
+static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+	bool link;
+
+	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		return ret_val;
+
+	if (!link) {
+		e_dbg("Phy info is only valid if link is up\n");
+		return -E1000_ERR_CONFIG;
+	}
+
+	ret_val = e1e_rphy(hw, IFE_PHY_SPECIAL_CONTROL, &data);
+	if (ret_val)
+		return ret_val;
+	phy->polarity_correction = (!(data & IFE_PSC_AUTO_POLARITY_DISABLE));
+
+	if (phy->polarity_correction) {
+		ret_val = phy->ops.check_polarity(hw);
+		if (ret_val)
+			return ret_val;
+	} else {
+		/* Polarity is forced */
+		phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY)
+				      ? e1000_rev_polarity_reversed
+				      : e1000_rev_polarity_normal;
+	}
+
+	ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data);
+	if (ret_val)
+		return ret_val;
+
+	phy->is_mdix = (data & IFE_PMC_MDIX_STATUS);
+
+	/* The following parameters are undefined for 10/100 operation. */
+	phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+	phy->local_rx = e1000_1000t_rx_status_undefined;
+	phy->remote_rx = e1000_1000t_rx_status_undefined;
+
+	return 0;
+}
+
+/**
+ *  e1000_get_phy_info_ich8lan - Calls appropriate PHY type get_info
+ *  @hw: pointer to the HW structure
+ *
+ *  Wrapper for calling the get_info routines for the appropriate phy type.
+ *  This is a function pointer entry point called by drivers
+ *  or other shared routines.
+ **/
+static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw)
+{
+	switch (hw->phy.type) {
+	case e1000_phy_ife:
+		return e1000_get_phy_info_ife_ich8lan(hw);
+		break;
+	case e1000_phy_igp_3:
+	case e1000_phy_bm:
+	case e1000_phy_82578:
+	case e1000_phy_82577:
+		return e1000e_get_phy_info_igp(hw);
+		break;
+	default:
+		break;
+	}
+
+	return -E1000_ERR_PHY_TYPE;
+}
+
+/**
  *  e1000_set_lplu_state_pchlan - Set Low Power Link Up state
  *  @hw: pointer to the HW structure
  *  @active: true to enable LPLU, false to disable
@@ -3394,8 +3550,10 @@ static struct e1000_phy_operations ich8_phy_ops = {
 	.acquire		= e1000_acquire_swflag_ich8lan,
 	.check_reset_block	= e1000_check_reset_block_ich8lan,
 	.commit			= NULL,
+	.force_speed_duplex	= e1000_phy_force_speed_duplex_ich8lan,
 	.get_cfg_done		= e1000_get_cfg_done_ich8lan,
 	.get_cable_length	= e1000e_get_cable_length_igp_2,
+	.get_info		= e1000_get_phy_info_ich8lan,
 	.read_reg		= e1000e_read_phy_reg_igp,
 	.release		= e1000_release_swflag_ich8lan,
 	.reset			= e1000_phy_hw_reset_ich8lan,

What seems to be happening here is a persistent failure of e1000e_get_phy_id, in both "slow" and "fast" MDI modes. However, in RHEL 5, this failure triggers a chain of workaround and adjustments that bring up the interface with some default parameters... which appear to work with my 1Gbit/s Netgear switch. So the hardware is not dead, or not completely dead.

Could someone come up with a fix here, please? I have no clue where to start even.

Greetings,
-- Pete

#1 lore raw
Quoted 14 lines · Pete Zaitcev

Dear All:

I have a box where e1000e would refuse to probe the onboard interface with the following in dmesg:

e1000e: Intel(R) PRO/1000 Network Driver - 1.0.2-k2
e1000e: Copyright (c) 1999 - 2009 Intel Corporation. e1000e 0000:00:19.0: PCI INT A -> GSI 20 (level, low) -> IRQ 20 e1000e 0000:00:19.0: setting latency timer to 64 e1000e 0000:00:19.0: irq 34 for MSI/MSI-X 0000:00:19.0: 0000:00:19.0: MDI Error
e1000e 0000:00:19.0: PCI INT A disabled
e1000e: probe of 0000:00:19.0 failed with error -2

Quoted 5 lines

The "MDI Error" seems to indicate a hardware failure, so I paid it no mind until I noticed that RHEL 5 works. So, I diffed the drivers between Linus' 2.6.34-rc5 and RHEL's 2.6.18-180.el5, with the following
minimal patch working for me:

Hi Pete,

Sorry you are having problems with e1000e. You didn't mention which LOM device was on this system - is the PCI device id 0x10ea, 0x10eb, 0x10ef or 0x10f0?

What BIOS version is on the system?

Would you be able to try a patch that is already in DaveM's net-next-2.6 tree? If so, it is http://git.kernel.org/?p=linux/kernel/git/davem/net-next-2.6.git;a=commitdiff;h=627c8a041f7aaaea93c766f69bd61d952a277586

Thanks,
Bruce.

#2 lore raw
Quoted 3 lines · Bruce W

Sorry you are having problems with e1000e. You didn't mention which LOM device was on this system - is the PCI device id 0x10ea, 0x10eb, 0x10ef or 0x10f0?

lspci -n says:

00:19.0 0200: 8086:10ef (rev 04)

Quoted 1 line

What BIOS version is on the system?

dmidecode says:

        Vendor: American Megatrends Inc.
        Version: 4.6.3
        Release Date: 05/22/2009
Quoted 3 lines

Would you be able to try a patch that is already in DaveM's net-next-2.6 tree? If so, it is
http://git.kernel.org/?p=linux/kernel/git/davem/net-next-2.6.git;a=commitdiff;h=627c8a041f7aaaea93c766f69bd61d952a277586

Thank you, this works. I guess I should've been more patient.

Yours,
-- Pete

#4 lore raw
Quoted 8 lines · Pete Zaitcev
Quoted 1 line · Bruce W

Would you be able to try a patch that is already in DaveM's net-next-2.6 tree? If so, it is http://git.kernel.org/?p=linux/kernel/git/davem/net-next-2.6.git;a=commitdiff;h=627c8a041f7aaaea93c766f69bd61d952a277586

I was too quick to claim victory here. I did an rmmod+insmod, it worked. Then I rebooted and it didn't. Weird...

That is exactly what I used to see on what I think is a similar system to Pete's. Pete and I have been talking and it looks like this system may need a BIOS update, so I'll see if we can work to get him an updated one.