[ipxe-devel] [PATCH] [e1000e] Basic 82579 support

Daniel Hokka Zakrisson daniel at hozac.com
Fri Apr 6 08:13:04 UTC 2012


Add support for 82579-based chips such as those found on Sandy Bridge
motherboards. Based on d3738bb8203acf8552c3ec8b3447133fc0938ddd in
Linux.

Signed-off-by: Daniel Hokka Zakrisson <daniel at hozac.com>
---
 src/drivers/net/e1000e/e1000e.h         |    2 +
 src/drivers/net/e1000e/e1000e_defines.h |    2 +
 src/drivers/net/e1000e/e1000e_hw.h      |    4 ++
 src/drivers/net/e1000e/e1000e_ich8lan.c |   51 ++++++++++++++++++++++---------
 src/drivers/net/e1000e/e1000e_ich8lan.h |    3 ++
 src/drivers/net/e1000e/e1000e_main.c    |   17 ++++++++++
 src/drivers/net/e1000e/e1000e_phy.c     |    3 ++
 7 files changed, 67 insertions(+), 15 deletions(-)

diff --git a/src/drivers/net/e1000e/e1000e.h b/src/drivers/net/e1000e/e1000e.h
index bc8e7b0..0e53793 100644
--- a/src/drivers/net/e1000e/e1000e.h
+++ b/src/drivers/net/e1000e/e1000e.h
@@ -143,6 +143,7 @@ enum e1000_boards {
 	board_ich9lan,
 	board_ich10lan,
 	board_pchlan,
+	board_pch2lan,
 	board_82583,
 };
 
@@ -300,6 +301,7 @@ extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
 extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
 extern void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw);
 extern void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw);
+extern s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable);
 
 extern s32 e1000e_check_for_copper_link(struct e1000_hw *hw);
 extern s32 e1000e_check_for_fiber_link(struct e1000_hw *hw);
diff --git a/src/drivers/net/e1000e/e1000e_defines.h b/src/drivers/net/e1000e/e1000e_defines.h
index da135d9..8cfc6ed 100644
--- a/src/drivers/net/e1000e/e1000e_defines.h
+++ b/src/drivers/net/e1000e/e1000e_defines.h
@@ -675,6 +675,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE       0x00000001
 #define E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE       0x00000008
 #define E1000_EXTCNF_CTRL_SWFLAG                 0x00000020
+#define E1000_EXTCNF_CTRL_GATE_PHY_CFG           0x00000080
 #define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK   0x00FF0000
 #define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT          16
 #define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK   0x0FFF0000
@@ -1261,6 +1262,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define BME1000_E_PHY_ID_R2  0x01410CB1
 #define I82577_E_PHY_ID 0x01540050
 #define I82578_E_PHY_ID 0x004DD040
+#define I82579_E_PHY_ID      0x01540090
 #define M88_VENDOR           0x0141
 
 /* M88E1000 Specific Registers */
diff --git a/src/drivers/net/e1000e/e1000e_hw.h b/src/drivers/net/e1000e/e1000e_hw.h
index 03ed35c..336af30 100644
--- a/src/drivers/net/e1000e/e1000e_hw.h
+++ b/src/drivers/net/e1000e/e1000e_hw.h
@@ -85,6 +85,8 @@ struct e1000_hw;
 #define E1000_DEV_ID_PCH_M_HV_LC              0x10EB
 #define E1000_DEV_ID_PCH_D_HV_DM              0x10EF
 #define E1000_DEV_ID_PCH_D_HV_DC              0x10F0
+#define E1000_DEV_ID_PCH2_LV_LM               0x1502
+#define E1000_DEV_ID_PCH2_LV_V                0x1503
 #define E1000_REVISION_0 0
 #define E1000_REVISION_1 1
 #define E1000_REVISION_2 2
@@ -109,6 +111,7 @@ enum e1000_mac_type {
 	e1000_ich9lan,
 	e1000_ich10lan,
 	e1000_pchlan,
+	e1000_pch2lan,
 	e1000_num_macs  /* List is 1-based, so subtract 1 for true count. */
 };
 
@@ -146,6 +149,7 @@ enum e1000_phy_type {
 	e1000_phy_bm,
 	e1000_phy_82578,
 	e1000_phy_82577,
+	e1000_phy_82579,
 };
 
 enum e1000_bus_type {
diff --git a/src/drivers/net/e1000e/e1000e_ich8lan.c b/src/drivers/net/e1000e/e1000e_ich8lan.c
index 7b9a49b..d438ff1 100644
--- a/src/drivers/net/e1000e/e1000e_ich8lan.c
+++ b/src/drivers/net/e1000e/e1000e_ich8lan.c
@@ -206,7 +206,7 @@ static s32 e1000e_init_phy_params_pchlan(struct e1000_hw *hw)
 	e1000e_get_phy_id(hw);
 	phy->type = e1000e_get_phy_type_from_id(phy->id);
 
-	if (phy->type == e1000_phy_82577) {
+	if (phy->type == e1000_phy_82577 || phy->type == e1000_phy_82579) {
 		phy->ops.check_polarity = e1000e_check_polarity_82577;
 #if 0
 		phy->ops.force_speed_duplex =
@@ -449,6 +449,7 @@ static s32 e1000e_init_mac_params_ich8lan(struct e1000_hw *hw)
 		mac->ops.led_off = e1000e_led_off_ich8lan;
 		break;
 	case e1000_pchlan:
+	case e1000_pch2lan:
 		/* ID LED init */
 		mac->ops.id_led_init = e1000e_id_led_init_pchlan;
 		/* setup LED */
@@ -467,6 +468,14 @@ static s32 e1000e_init_mac_params_ich8lan(struct e1000_hw *hw)
 	if (mac->type == e1000_ich8lan)
 		e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, true);
 
+	/* Disable PHY configuration by hardware, config by software */
+	if (mac->type == e1000_pch2lan) {
+		u32 extcnf_ctrl = er32(EXTCNF_CTRL);
+
+		extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG;
+		ew32(EXTCNF_CTRL, extcnf_ctrl);
+	}
+
 
 	return E1000_SUCCESS;
 }
@@ -577,6 +586,7 @@ void e1000e_init_function_pointers_ich8lan(struct e1000_hw *hw)
 		hw->phy.ops.init_params = e1000e_init_phy_params_ich8lan;
 		break;
 	case e1000_pchlan:
+	case e1000_pch2lan:
 		hw->phy.ops.init_params = e1000e_init_phy_params_pchlan;
 		break;
 	default:
@@ -765,7 +775,8 @@ static s32 e1000e_sw_lcd_config_ich8lan(struct e1000_hw *hw)
 		/* Check if SW needs to configure the PHY */
 		if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT) ||
 		    (hw->device_id == E1000_DEV_ID_ICH8_IGP_M) ||
-		    (hw->mac.type == e1000_pchlan))
+		    (hw->mac.type == e1000_pchlan) ||
+		    (hw->mac.type == e1000_pch2lan))
 			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
 		else
 			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
@@ -777,13 +788,15 @@ static s32 e1000e_sw_lcd_config_ich8lan(struct e1000_hw *hw)
 		/* Wait for basic configuration completes before proceeding */
 		e1000e_lan_init_done_ich8lan(hw);
 
-		/*
-		 * Make sure HW does not configure LCD from PHY
-		 * extended configuration before SW configuration
-		 */
-		data = er32(EXTCNF_CTRL);
-		if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
-			goto out;
+		if (hw->mac.type != e1000_pch2lan) {
+			/*
+			 * Make sure HW does not configure LCD from PHY
+			 * extended configuration before SW configuration
+			 */
+			data = er32(EXTCNF_CTRL);
+			if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
+				goto out;
+		}
 
 		cnf_size = er32(EXTCNF_SIZE);
 		cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
@@ -795,7 +808,8 @@ static s32 e1000e_sw_lcd_config_ich8lan(struct e1000_hw *hw)
 		cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
 
 		if (!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) &&
-		    (hw->mac.type == e1000_pchlan)) {
+		    (hw->mac.type == e1000_pchlan ||
+		     hw->mac.type == e1000_pch2lan)) {
 			/*
 			 * HW configures the SMBus address and LEDs when the
 			 * OEM and LCD Write Enable bits are set in the NVM.
@@ -1006,16 +1020,18 @@ s32 e1000e_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state)
 	u32 mac_reg;
 	u16 oem_reg;
 
-	if (hw->mac.type != e1000_pchlan)
+	if (hw->mac.type != e1000_pchlan && hw->mac.type != e1000_pch2lan)
 		return ret_val;
 
 	ret_val = hw->phy.ops.acquire(hw);
 	if (ret_val)
 		return ret_val;
 
-	mac_reg = er32(EXTCNF_CTRL);
-	if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
-		goto out;
+	if (hw->mac.type != e1000_pch2lan) {
+		mac_reg = er32(EXTCNF_CTRL);
+		if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
+			goto out;
+	}
 
 	mac_reg = er32(FEXTNVM);
 	if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M))
@@ -2573,7 +2589,7 @@ static s32 e1000e_reset_hw_ich8lan(struct e1000_hw *hw)
 		}
 	}
 	/* Dummy read to clear the phy wakeup bit after lcd reset */
-	if (hw->mac.type == e1000_pchlan)
+	if (hw->mac.type == e1000_pchlan || hw->mac.type == e1000_pch2lan)
 		e1e_rphy(hw, BM_WUC, &reg);
 
 	ret_val = e1000e_sw_lcd_config_ich8lan(hw);
@@ -2791,6 +2807,7 @@ static s32 e1000e_setup_link_ich8lan(struct e1000_hw *hw)
 
 	ew32(FCTTV, hw->fc.pause_time);
 	if ((hw->phy.type == e1000_phy_82578) ||
+	    (hw->phy.type == e1000_phy_82579) ||
 	    (hw->phy.type == e1000_phy_82577)) {
 		ret_val = e1e_wphy(hw,
 		                             PHY_REG(BM_PORT_CTRL_PAGE, 27),
@@ -2859,6 +2876,7 @@ static s32 e1000e_setup_copper_link_ich8lan(struct e1000_hw *hw)
 			goto out;
 		break;
 	case e1000_phy_82577:
+	case e1000_phy_82579:
 		ret_val = e1000e_copper_link_setup_82577(hw);
 		if (ret_val)
 			goto out;
@@ -3388,6 +3406,7 @@ static void e1000e_clear_hw_cntrs_ich8lan(struct e1000_hw *hw __unused)
 
 	/* Clear PHY statistics registers */
 	if ((hw->phy.type == e1000_phy_82578) ||
+	    (hw->phy.type == e1000_phy_82579) ||
 	    (hw->phy.type == e1000_phy_82577)) {
 		e1e_rphy(hw, HV_SCC_UPPER, &phy_data);
 		e1e_rphy(hw, HV_SCC_LOWER, &phy_data);
@@ -3434,6 +3453,8 @@ static struct pci_device_id e1000e_ich8lan_nics[] = {
      PCI_ROM(0x8086, 0x10EB, "E1000_DEV_ID_PCH_M_HV_LC", "E1000_DEV_ID_PCH_M_HV_LC", board_pchlan),
      PCI_ROM(0x8086, 0x10EF, "E1000_DEV_ID_PCH_D_HV_DM", "E1000_DEV_ID_PCH_D_HV_DM", board_pchlan),
      PCI_ROM(0x8086, 0x10F0, "E1000_DEV_ID_PCH_D_HV_DC", "E1000_DEV_ID_PCH_D_HV_DC", board_pchlan),
+     PCI_ROM(0x8086, 0x1502, "E1000_DEV_ID_PCH2_LV_LM", "E1000_DEV_ID_PCH2_LV_LM", board_pch2lan),
+     PCI_ROM(0x8086, 0x1503, "E1000_DEV_ID_PCH2_LV_V", "E1000_DEV_ID_PCH2_LV_V", board_pch2lan),
 };
 
 struct pci_driver e1000e_ich8lan_driver __pci_driver = {
diff --git a/src/drivers/net/e1000e/e1000e_ich8lan.h b/src/drivers/net/e1000e/e1000e_ich8lan.h
index af34478..8b145d9 100644
--- a/src/drivers/net/e1000e/e1000e_ich8lan.h
+++ b/src/drivers/net/e1000e/e1000e_ich8lan.h
@@ -146,6 +146,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define HV_SMB_ADDR_PEC_EN     0x0200
 #define HV_SMB_ADDR_VALID      0x0080
 
+/* PHY Power Management Control */
+#define HV_PM_CTRL             PHY_REG(770, 17)
+
 /* Strapping Option Register - RO */
 #define E1000_STRAP                     0x0000C
 #define E1000_STRAP_SMBUS_ADDRESS_MASK  0x00FE0000
diff --git a/src/drivers/net/e1000e/e1000e_main.c b/src/drivers/net/e1000e/e1000e_main.c
index 352e3c4..69a5bc2 100644
--- a/src/drivers/net/e1000e/e1000e_main.c
+++ b/src/drivers/net/e1000e/e1000e_main.c
@@ -279,6 +279,22 @@ static struct e1000_info e1000_pch_info = {
 	.get_variants		= e1000e_get_variants_ich8lan,
 };
 
+static struct e1000_info e1000_pch2_info = {
+	.mac			= e1000_pch2lan,
+	.flags			= FLAG_IS_ICH
+				  | FLAG_HAS_WOL
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_CTRLEXT_ON_LOAD
+				  | FLAG_HAS_AMT
+				  | FLAG_HAS_FLASH
+				  | FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_APME_IN_WUC,
+	.pba			= 26,
+	.max_hw_frame_size	= DEFAULT_JUMBO,
+	.init_ops		= e1000e_init_function_pointers_ich8lan,
+	.get_variants		= e1000e_get_variants_ich8lan,
+};
+
 static const struct e1000_info *e1000_info_tbl[] = {
 	[board_82571]		= &e1000_82571_info,
 	[board_82572]		= &e1000_82572_info,
@@ -290,6 +306,7 @@ static const struct e1000_info *e1000_info_tbl[] = {
 	[board_ich9lan]		= &e1000_ich9_info,
 	[board_ich10lan]	= &e1000_ich10_info,
 	[board_pchlan]		= &e1000_pch_info,
+	[board_pch2lan]		= &e1000_pch2_info,
 };
 
 /* Low-level support routines */
diff --git a/src/drivers/net/e1000e/e1000e_phy.c b/src/drivers/net/e1000e/e1000e_phy.c
index 337be73..133109d 100644
--- a/src/drivers/net/e1000e/e1000e_phy.c
+++ b/src/drivers/net/e1000e/e1000e_phy.c
@@ -2332,6 +2332,9 @@ enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id)
 	case I82577_E_PHY_ID:
 		phy_type = e1000_phy_82577;
 		break;
+	case I82579_E_PHY_ID:
+		phy_type = e1000_phy_82579;
+		break;
 	default:
 		phy_type = e1000_phy_unknown;
 		break;
-- 
1.7.6.5




More information about the ipxe-devel mailing list