aboutsummaryrefslogtreecommitdiff
path: root/src/drivers
diff options
context:
space:
mode:
authorDaniel Hokka Zakrisson <daniel@hozac.com>2012-04-06 10:13:04 +0200
committerMichael Brown <mcb30@ipxe.org>2012-04-10 13:47:19 +0100
commit0e4a5ca4c73bc7f264616a0032d60e40c99e6710 (patch)
treef5ac2112cc6199b132b5af55331894aed144c828 /src/drivers
parentdcccb1fb7bb79bdd018b23ca203d26cca98a1d3f (diff)
downloadipxe-0e4a5ca4c73bc7f264616a0032d60e40c99e6710.zip
ipxe-0e4a5ca4c73bc7f264616a0032d60e40c99e6710.tar.gz
ipxe-0e4a5ca4c73bc7f264616a0032d60e40c99e6710.tar.bz2
[e1000e] Basic 82579 support
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@hozac.com> Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/net/e1000e/e1000e.h2
-rw-r--r--src/drivers/net/e1000e/e1000e_defines.h2
-rw-r--r--src/drivers/net/e1000e/e1000e_hw.h4
-rw-r--r--src/drivers/net/e1000e/e1000e_ich8lan.c51
-rw-r--r--src/drivers/net/e1000e/e1000e_ich8lan.h3
-rw-r--r--src/drivers/net/e1000e/e1000e_main.c17
-rw-r--r--src/drivers/net/e1000e/e1000e_phy.c3
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;