summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjfv <jfv@FreeBSD.org>2012-07-05 20:26:57 +0000
committerjfv <jfv@FreeBSD.org>2012-07-05 20:26:57 +0000
commit2fed9a44b5cd7453b3deb44612cd428de42910c8 (patch)
tree4c99f5b2313b82cc2b3071e0ab987ed5b90cb256
parenta4e243117eff56b96f000b878b431be3f67058df (diff)
downloadFreeBSD-src-2fed9a44b5cd7453b3deb44612cd428de42910c8.zip
FreeBSD-src-2fed9a44b5cd7453b3deb44612cd428de42910c8.tar.gz
Sync with Intel internal source:
shared code update and small changes in core required Add support for new i210/i211 devices Improve queue calculation based on mac type MFC after:5 days
-rw-r--r--sys/conf/files2
-rw-r--r--sys/dev/e1000/e1000_82541.c2
-rw-r--r--sys/dev/e1000/e1000_82543.c8
-rw-r--r--sys/dev/e1000/e1000_82571.c2
-rw-r--r--sys/dev/e1000/e1000_82575.c195
-rw-r--r--sys/dev/e1000/e1000_api.c17
-rw-r--r--sys/dev/e1000/e1000_api.h4
-rw-r--r--sys/dev/e1000/e1000_defines.h38
-rw-r--r--sys/dev/e1000/e1000_hw.h19
-rw-r--r--sys/dev/e1000/e1000_i210.c740
-rw-r--r--sys/dev/e1000/e1000_i210.h80
-rw-r--r--sys/dev/e1000/e1000_ich8lan.c2
-rw-r--r--sys/dev/e1000/e1000_mac.c598
-rw-r--r--sys/dev/e1000/e1000_mac.h12
-rw-r--r--sys/dev/e1000/e1000_manage.c324
-rw-r--r--sys/dev/e1000/e1000_manage.h60
-rw-r--r--sys/dev/e1000/e1000_phy.c1015
-rw-r--r--sys/dev/e1000/e1000_phy.h24
-rw-r--r--sys/dev/e1000/e1000_regs.h75
-rw-r--r--sys/dev/e1000/if_em.c2
-rw-r--r--sys/dev/e1000/if_igb.c122
-rw-r--r--sys/modules/igb/Makefile2
22 files changed, 2262 insertions, 1081 deletions
diff --git a/sys/conf/files b/sys/conf/files
index 4d4c0bc..2a569b2 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1196,6 +1196,8 @@ dev/e1000/e1000_82575.c optional em | igb \
compile-with "${NORMAL_C} -I$S/dev/e1000"
dev/e1000/e1000_ich8lan.c optional em | igb \
compile-with "${NORMAL_C} -I$S/dev/e1000"
+dev/e1000/e1000_i210.c optional em | igb \
+ compile-with "${NORMAL_C} -I$S/dev/e1000"
dev/e1000/e1000_api.c optional em | igb \
compile-with "${NORMAL_C} -I$S/dev/e1000"
dev/e1000/e1000_mac.c optional em | igb \
diff --git a/sys/dev/e1000/e1000_82541.c b/sys/dev/e1000/e1000_82541.c
index d13611e..781aa93 100644
--- a/sys/dev/e1000/e1000_82541.c
+++ b/sys/dev/e1000/e1000_82541.c
@@ -642,7 +642,7 @@ static s32 e1000_check_for_link_82541(struct e1000_hw *hw)
* of MAC speed/duplex configuration. So we only need to
* configure Collision Distance in the MAC.
*/
- e1000_config_collision_dist_generic(hw);
+ mac->ops.config_collision_dist(hw);
/*
* Configure Flow Control now that Auto-Neg has completed.
diff --git a/sys/dev/e1000/e1000_82543.c b/sys/dev/e1000/e1000_82543.c
index 1507da5..1c01658 100644
--- a/sys/dev/e1000/e1000_82543.c
+++ b/sys/dev/e1000/e1000_82543.c
@@ -1126,7 +1126,7 @@ static s32 e1000_setup_copper_link_82543(struct e1000_hw *hw)
DEBUGOUT("Valid link established!!!\n");
/* Config the MAC and PHY after link is up */
if (hw->mac.type == e1000_82544) {
- e1000_config_collision_dist_generic(hw);
+ hw->mac.ops.config_collision_dist(hw);
} else {
ret_val = e1000_config_mac_to_phy_82543(hw);
if (ret_val)
@@ -1160,7 +1160,7 @@ static s32 e1000_setup_fiber_link_82543(struct e1000_hw *hw)
/* Take the link out of reset */
ctrl &= ~E1000_CTRL_LRST;
- e1000_config_collision_dist_generic(hw);
+ hw->mac.ops.config_collision_dist(hw);
ret_val = e1000_commit_fc_settings_generic(hw);
if (ret_val)
@@ -1259,7 +1259,7 @@ static s32 e1000_check_for_copper_link_82543(struct e1000_hw *hw)
* settings.
*/
if (mac->type == e1000_82544)
- e1000_config_collision_dist_generic(hw);
+ hw->mac.ops.config_collision_dist(hw);
else {
ret_val = e1000_config_mac_to_phy_82543(hw);
if (ret_val) {
@@ -1433,7 +1433,7 @@ static s32 e1000_config_mac_to_phy_82543(struct e1000_hw *hw)
if (phy_data & M88E1000_PSSR_DPLX)
ctrl |= E1000_CTRL_FD;
- e1000_config_collision_dist_generic(hw);
+ hw->mac.ops.config_collision_dist(hw);
/*
* Set up speed in the Device Control register depending on
diff --git a/sys/dev/e1000/e1000_82571.c b/sys/dev/e1000/e1000_82571.c
index a2982b9..30015c1 100644
--- a/sys/dev/e1000/e1000_82571.c
+++ b/sys/dev/e1000/e1000_82571.c
@@ -1907,7 +1907,7 @@ void e1000_set_laa_state_82571(struct e1000_hw *hw, bool state)
* incoming packets directed to this port are dropped.
* Eventually the LAA will be in RAR[0] and RAR[14].
*/
- e1000_rar_set_generic(hw, hw->mac.addr,
+ hw->mac.ops.rar_set(hw, hw->mac.addr,
hw->mac.rar_entry_count - 1);
return;
}
diff --git a/sys/dev/e1000/e1000_82575.c b/sys/dev/e1000/e1000_82575.c
index 75fe0a4..a04e3fa 100644
--- a/sys/dev/e1000/e1000_82575.c
+++ b/sys/dev/e1000/e1000_82575.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2011, Intel Corporation
+ Copyright (c) 2001-2012, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -38,9 +38,12 @@
* 82575GB Gigabit Network Connection
* 82576 Gigabit Network Connection
* 82576 Quad Port Gigabit Mezzanine Adapter
+ * 82580 Gigabit Network Connection
+ * I350 Gigabit Network Connection
*/
#include "e1000_api.h"
+#include "e1000_i210.h"
static s32 e1000_init_phy_params_82575(struct e1000_hw *hw);
static s32 e1000_init_mac_params_82575(struct e1000_hw *hw);
@@ -162,6 +165,9 @@ static s32 e1000_init_phy_params_82575(struct e1000_hw *hw)
DEBUGFUNC("e1000_init_phy_params_82575");
+ phy->ops.read_i2c_byte = e1000_read_i2c_byte_generic;
+ phy->ops.write_i2c_byte = e1000_write_i2c_byte_generic;
+
if (hw->phy.media_type != e1000_media_type_copper) {
phy->type = e1000_phy_none;
goto out;
@@ -195,12 +201,22 @@ static s32 e1000_init_phy_params_82575(struct e1000_hw *hw)
if (e1000_sgmii_active_82575(hw) && !e1000_sgmii_uses_mdio_82575(hw)) {
phy->ops.read_reg = e1000_read_phy_reg_sgmii_82575;
phy->ops.write_reg = e1000_write_phy_reg_sgmii_82575;
- } else if (hw->mac.type >= e1000_82580) {
- phy->ops.read_reg = e1000_read_phy_reg_82580;
- phy->ops.write_reg = e1000_write_phy_reg_82580;
} else {
- phy->ops.read_reg = e1000_read_phy_reg_igp;
- phy->ops.write_reg = e1000_write_phy_reg_igp;
+ switch (hw->mac.type) {
+ case e1000_82580:
+ case e1000_i350:
+ phy->ops.read_reg = e1000_read_phy_reg_82580;
+ phy->ops.write_reg = e1000_write_phy_reg_82580;
+ break;
+ case e1000_i210:
+ case e1000_i211:
+ phy->ops.read_reg = e1000_read_phy_reg_gs40g;
+ phy->ops.write_reg = e1000_write_phy_reg_gs40g;
+ break;
+ default:
+ phy->ops.read_reg = e1000_read_phy_reg_igp;
+ phy->ops.write_reg = e1000_write_phy_reg_igp;
+ }
}
/* Set phy->phy_addr and phy->id. */
@@ -245,6 +261,15 @@ static s32 e1000_init_phy_params_82575(struct e1000_hw *hw)
phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_82580;
phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_82580;
break;
+ case I210_I_PHY_ID:
+ phy->type = e1000_phy_i210;
+ phy->ops.check_polarity = e1000_check_polarity_m88;
+ phy->ops.get_info = e1000_get_phy_info_m88;
+ phy->ops.get_cable_length = e1000_get_cable_length_m88_gen2;
+ phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_82580;
+ phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_82580;
+ phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
+ break;
default:
ret_val = -E1000_ERR_PHY;
goto out;
@@ -281,28 +306,32 @@ s32 e1000_init_nvm_params_82575(struct e1000_hw *hw)
size = 15;
nvm->word_size = 1 << size;
- nvm->opcode_bits = 8;
- nvm->delay_usec = 1;
- switch (nvm->override) {
- case e1000_nvm_override_spi_large:
- nvm->page_size = 32;
- nvm->address_bits = 16;
- break;
- case e1000_nvm_override_spi_small:
- nvm->page_size = 8;
- nvm->address_bits = 8;
- break;
- default:
- nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
- nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
- break;
- }
-
- nvm->type = e1000_nvm_eeprom_spi;
-
- if (nvm->word_size == (1 << 15))
- nvm->page_size = 128;
+ if (hw->mac.type < e1000_i210) {
+ nvm->opcode_bits = 8;
+ nvm->delay_usec = 1;
+
+ switch (nvm->override) {
+ case e1000_nvm_override_spi_large:
+ nvm->page_size = 32;
+ nvm->address_bits = 16;
+ break;
+ case e1000_nvm_override_spi_small:
+ nvm->page_size = 8;
+ nvm->address_bits = 8;
+ break;
+ default:
+ nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+ nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ?
+ 16 : 8;
+ break;
+ }
+ if (nvm->word_size == (1 << 15))
+ nvm->page_size = 128;
+ nvm->type = e1000_nvm_eeprom_spi;
+ } else {
+ nvm->type = e1000_nvm_flash_hw;
+ }
/* Function Pointers */
nvm->ops.acquire = e1000_acquire_nvm_82575;
nvm->ops.release = e1000_release_nvm_82575;
@@ -316,7 +345,7 @@ s32 e1000_init_nvm_params_82575(struct e1000_hw *hw)
nvm->ops.update = e1000_update_nvm_checksum_generic;
nvm->ops.valid_led_default = e1000_valid_led_default_82575;
- /* override genric family function pointers for specific descendants */
+ /* override generic family function pointers for specific descendants */
switch (hw->mac.type) {
case e1000_82580:
nvm->ops.validate = e1000_validate_nvm_checksum_82580;
@@ -368,8 +397,7 @@ static s32 e1000_init_mac_params_82575(struct e1000_hw *hw)
mac->has_fwsm = TRUE;
/* ARC supported; valid only if manageability features are enabled. */
mac->arc_subsystem_valid =
- (E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_MODE_MASK)
- ? TRUE : FALSE;
+ !!(E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_MODE_MASK);
/* Function pointers */
@@ -394,8 +422,6 @@ static s32 e1000_init_mac_params_82575(struct e1000_hw *hw)
mac->ops.power_up_serdes = e1000_power_up_serdes_link_82575;
/* check for link */
mac->ops.check_for_link = e1000_check_for_link_82575;
- /* receive address register setting */
- mac->ops.rar_set = e1000_rar_set_generic;
/* read mac address */
mac->ops.read_mac_addr = e1000_read_mac_addr_82575;
/* configure collision distance */
@@ -428,6 +454,13 @@ static s32 e1000_init_mac_params_82575(struct e1000_hw *hw)
mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82575;
/* link info */
mac->ops.get_link_up_info = e1000_get_link_up_info_82575;
+ /* acquire SW_FW sync */
+ mac->ops.acquire_swfw_sync = e1000_acquire_swfw_sync_82575;
+ mac->ops.release_swfw_sync = e1000_release_swfw_sync_82575;
+ if (mac->type >= e1000_i210) {
+ mac->ops.acquire_swfw_sync = e1000_acquire_swfw_sync_i210;
+ mac->ops.release_swfw_sync = e1000_release_swfw_sync_i210;
+ }
/* set lan id for port to determine which phy lock to use */
hw->mac.ops.set_lan_id(hw);
@@ -470,7 +503,7 @@ static s32 e1000_acquire_phy_82575(struct e1000_hw *hw)
else if (hw->bus.func == E1000_FUNC_3)
mask = E1000_SWFW_PHY3_SM;
- return e1000_acquire_swfw_sync_82575(hw, mask);
+ return hw->mac.ops.acquire_swfw_sync(hw, mask);
}
/**
@@ -492,7 +525,7 @@ static void e1000_release_phy_82575(struct e1000_hw *hw)
else if (hw->bus.func == E1000_FUNC_3)
mask = E1000_SWFW_PHY3_SM;
- e1000_release_swfw_sync_82575(hw, mask);
+ hw->mac.ops.release_swfw_sync(hw, mask);
}
/**
@@ -796,7 +829,7 @@ static s32 e1000_set_d0_lplu_state_82580(struct e1000_hw *hw, bool active)
{
struct e1000_phy_info *phy = &hw->phy;
s32 ret_val = E1000_SUCCESS;
- u16 data;
+ u32 data;
DEBUGFUNC("e1000_set_d0_lplu_state_82580");
@@ -844,7 +877,7 @@ s32 e1000_set_d3_lplu_state_82580(struct e1000_hw *hw, bool active)
{
struct e1000_phy_info *phy = &hw->phy;
s32 ret_val = E1000_SUCCESS;
- u16 data;
+ u32 data;
DEBUGFUNC("e1000_set_d3_lplu_state_82580");
@@ -918,11 +951,7 @@ static s32 e1000_acquire_nvm_82575(struct e1000_hw *hw)
}
- switch (hw->mac.type) {
- default:
- ret_val = e1000_acquire_nvm_generic(hw);
- }
-
+ ret_val = e1000_acquire_nvm_generic(hw);
if (ret_val)
e1000_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
@@ -941,10 +970,8 @@ static void e1000_release_nvm_82575(struct e1000_hw *hw)
{
DEBUGFUNC("e1000_release_nvm_82575");
- switch (hw->mac.type) {
- default:
- e1000_release_nvm_generic(hw);
- }
+ e1000_release_nvm_generic(hw);
+
e1000_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
}
@@ -1058,7 +1085,7 @@ static s32 e1000_get_cfg_done_82575(struct e1000_hw *hw)
DEBUGOUT("MNG configuration cycle has not completed.\n");
/* If EEPROM is not marked present, init the PHY manually */
- if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) &&
+ if (!(E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) &&
(hw->phy.type == e1000_phy_igp_3))
e1000_phy_init_script_igp3(hw);
@@ -1115,6 +1142,7 @@ static s32 e1000_check_for_link_82575(struct e1000_hw *hw)
* continue to check for link.
*/
hw->mac.get_link_status = !hw->mac.serdes_has_link;
+
} else {
ret_val = e1000_check_for_copper_link_generic(hw);
}
@@ -1168,11 +1196,6 @@ static s32 e1000_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw,
DEBUGFUNC("e1000_get_pcs_speed_and_duplex_82575");
- /* Set up defaults for the return values of this function */
- mac->serdes_has_link = FALSE;
- *speed = 0;
- *duplex = 0;
-
/*
* Read the PCS Status register for link state. For non-copper mode,
* the status register is not accurate. The PCS status register is
@@ -1181,11 +1204,9 @@ static s32 e1000_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw,
pcs = E1000_READ_REG(hw, E1000_PCS_LSTAT);
/*
- * The link up bit determines when link is up on autoneg. The sync ok
- * gets set once both sides sync up and agree upon link. Stable link
- * can be determined by checking for both link up and link sync ok
+ * The link up bit determines when link is up on autoneg.
*/
- if ((pcs & E1000_PCS_LSTS_LINK_OK) && (pcs & E1000_PCS_LSTS_SYNK_OK)) {
+ if (pcs & E1000_PCS_LSTS_LINK_OK) {
mac->serdes_has_link = TRUE;
/* Detect and store PCS speed */
@@ -1201,6 +1222,10 @@ static s32 e1000_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw,
*duplex = FULL_DUPLEX;
else
*duplex = HALF_DUPLEX;
+ } else {
+ mac->serdes_has_link = FALSE;
+ *speed = 0;
+ *duplex = 0;
}
return E1000_SUCCESS;
@@ -1293,7 +1318,7 @@ static s32 e1000_reset_hw_82575(struct e1000_hw *hw)
}
/* If EEPROM is not present, run manual init scripts */
- if ((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0)
+ if (!(E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES))
e1000_reset_init_script_82575(hw);
/* Clear any pending interrupt events. */
@@ -1396,6 +1421,7 @@ static s32 e1000_setup_copper_link_82575(struct e1000_hw *hw)
}
}
switch (hw->phy.type) {
+ case e1000_phy_i210:
case e1000_phy_m88:
if (hw->phy.id == I347AT4_E_PHY_ID ||
hw->phy.id == M88E1112_E_PHY_ID ||
@@ -1605,31 +1631,28 @@ static s32 e1000_get_media_type_82575(struct e1000_hw *hw)
}
/* Read Init Control Word #3*/
hw->nvm.ops.read(hw, init_ctrl_wd_3_offset, 1, &init_ctrl_wd_3);
+
+ /*
+ * Align link mode bits to
+ * their CTRL_EXT location.
+ */
current_link_mode = init_ctrl_wd_3;
+ current_link_mode <<= (E1000_CTRL_EXT_LINK_MODE_OFFSET -
+ init_ctrl_wd_3_bit_offset);
+ current_link_mode &= E1000_CTRL_EXT_LINK_MODE_MASK;
+
/*
* Switch to CSR for all but internal PHY.
*/
- if ((init_ctrl_wd_3 << (E1000_CTRL_EXT_LINK_MODE_OFFSET -
- init_ctrl_wd_3_bit_offset)) !=
- E1000_CTRL_EXT_LINK_MODE_GMII) {
- current_link_mode = ctrl_ext;
- init_ctrl_wd_3_bit_offset =
- E1000_CTRL_EXT_LINK_MODE_OFFSET;
- }
+ if (current_link_mode != E1000_CTRL_EXT_LINK_MODE_GMII)
+ /* Take link mode from CSR */
+ current_link_mode = ctrl_ext &
+ E1000_CTRL_EXT_LINK_MODE_MASK;
} else {
/* Take link mode from CSR */
- current_link_mode = ctrl_ext;
- init_ctrl_wd_3_bit_offset = E1000_CTRL_EXT_LINK_MODE_OFFSET;
+ current_link_mode = ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK;
}
- /*
- * Align link mode bits to
- * their CTRL_EXT location.
- */
- current_link_mode <<= (E1000_CTRL_EXT_LINK_MODE_OFFSET -
- init_ctrl_wd_3_bit_offset);
- current_link_mode &= E1000_CTRL_EXT_LINK_MODE_MASK;
-
switch (current_link_mode) {
case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX:
@@ -2331,7 +2354,7 @@ static s32 e1000_reset_hw_82580(struct e1000_hw *hw)
msec_delay(10);
/* Determine whether or not a global dev reset is requested */
- if (global_device_reset && e1000_acquire_swfw_sync_82575(hw,
+ if (global_device_reset && hw->mac.ops.acquire_swfw_sync(hw,
swmbsw_mask))
global_device_reset = FALSE;
@@ -2359,7 +2382,7 @@ static s32 e1000_reset_hw_82580(struct e1000_hw *hw)
}
/* If EEPROM is not present, run manual init scripts */
- if ((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0)
+ if (!(E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES))
e1000_reset_init_script_82575(hw);
/* clear global device reset status bit */
@@ -2378,7 +2401,7 @@ static s32 e1000_reset_hw_82580(struct e1000_hw *hw)
/* Release semaphore */
if (global_device_reset)
- e1000_release_swfw_sync_82575(hw, swmbsw_mask);
+ hw->mac.ops.release_swfw_sync(hw, swmbsw_mask);
return ret_val;
}
@@ -2538,7 +2561,7 @@ static s32 e1000_update_nvm_checksum_82580(struct e1000_hw *hw)
goto out;
}
- if ((nvm_data & NVM_COMPATIBILITY_BIT_MASK) == 0) {
+ if (!(nvm_data & NVM_COMPATIBILITY_BIT_MASK)) {
/* set compatibility bit to validate checksums appropriately */
nvm_data = nvm_data | NVM_COMPATIBILITY_BIT_MASK;
ret_val = hw->nvm.ops.write(hw, NVM_COMPATIBILITY_REG_3, 1,
@@ -2737,6 +2760,7 @@ s32 e1000_set_i2c_bb(struct e1000_hw *hw)
* e1000_read_i2c_byte_generic - Reads 8 bit word over I2C
* @hw: pointer to hardware structure
* @byte_offset: byte offset to read
+ * @dev_addr: device address
* @data: value read
*
* Performs byte read operation over I2C interface at
@@ -2750,14 +2774,14 @@ s32 e1000_read_i2c_byte_generic(struct e1000_hw *hw, u8 byte_offset,
u32 retry = 1;
u16 swfw_mask = 0;
- bool nack = 1;
+ bool nack = TRUE;
DEBUGFUNC("e1000_read_i2c_byte_generic");
swfw_mask = E1000_SWFW_PHY0_SM;
do {
- if (e1000_acquire_swfw_sync_82575(hw, swfw_mask)
+ if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)
!= E1000_SUCCESS) {
status = E1000_ERR_SWFW_SYNC;
goto read_byte_out;
@@ -2805,7 +2829,7 @@ s32 e1000_read_i2c_byte_generic(struct e1000_hw *hw, u8 byte_offset,
break;
fail:
- e1000_release_swfw_sync_82575(hw, swfw_mask);
+ hw->mac.ops.release_swfw_sync(hw, swfw_mask);
msec_delay(100);
e1000_i2c_bus_clear(hw);
retry++;
@@ -2816,7 +2840,7 @@ fail:
} while (retry < max_retry);
- e1000_release_swfw_sync_82575(hw, swfw_mask);
+ hw->mac.ops.release_swfw_sync(hw, swfw_mask);
read_byte_out:
@@ -2827,6 +2851,7 @@ read_byte_out:
* e1000_write_i2c_byte_generic - Writes 8 bit word over I2C
* @hw: pointer to hardware structure
* @byte_offset: byte offset to write
+ * @dev_addr: device address
* @data: value to write
*
* Performs byte write operation over I2C interface at
@@ -2844,7 +2869,7 @@ s32 e1000_write_i2c_byte_generic(struct e1000_hw *hw, u8 byte_offset,
swfw_mask = E1000_SWFW_PHY0_SM;
- if (e1000_acquire_swfw_sync_82575(hw, swfw_mask) != E1000_SUCCESS) {
+ if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) != E1000_SUCCESS) {
status = E1000_ERR_SWFW_SYNC;
goto write_byte_out;
}
@@ -2888,7 +2913,7 @@ fail:
DEBUGOUT("I2C byte write error.\n");
} while (retry < max_retry);
- e1000_release_swfw_sync_82575(hw, swfw_mask);
+ hw->mac.ops.release_swfw_sync(hw, swfw_mask);
write_byte_out:
@@ -3020,7 +3045,7 @@ static s32 e1000_get_i2c_ack(struct e1000_hw *hw)
u32 i = 0;
u32 i2cctl = E1000_READ_REG(hw, E1000_I2CPARAMS);
u32 timeout = 10;
- bool ack = 1;
+ bool ack = TRUE;
DEBUGFUNC("e1000_get_i2c_ack");
@@ -3040,7 +3065,7 @@ static s32 e1000_get_i2c_ack(struct e1000_hw *hw)
return E1000_ERR_I2C;
ack = e1000_get_i2c_data(&i2cctl);
- if (ack == 1) {
+ if (ack) {
DEBUGOUT("I2C ack was not received.\n");
status = E1000_ERR_I2C;
}
diff --git a/sys/dev/e1000/e1000_api.c b/sys/dev/e1000/e1000_api.c
index fdfc4bb..4b2a43d 100644
--- a/sys/dev/e1000/e1000_api.c
+++ b/sys/dev/e1000/e1000_api.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2011, Intel Corporation
+ Copyright (c) 2001-2012, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -323,6 +323,17 @@ s32 e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_I350_DA4:
mac->type = e1000_i350;
break;
+ case E1000_DEV_ID_I210_COPPER:
+ case E1000_DEV_ID_I210_COPPER_OEM1:
+ case E1000_DEV_ID_I210_COPPER_IT:
+ case E1000_DEV_ID_I210_FIBER:
+ case E1000_DEV_ID_I210_SERDES:
+ case E1000_DEV_ID_I210_SGMII:
+ mac->type = e1000_i210;
+ break;
+ case E1000_DEV_ID_I211_COPPER:
+ mac->type = e1000_i211;
+ break;
case E1000_DEV_ID_82576_VF:
mac->type = e1000_vfadapt;
break;
@@ -425,6 +436,10 @@ s32 e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device)
case e1000_i350:
e1000_init_function_pointers_82575(hw);
break;
+ case e1000_i210:
+ case e1000_i211:
+ e1000_init_function_pointers_i210(hw);
+ break;
case e1000_vfadapt:
e1000_init_function_pointers_vf(hw);
break;
diff --git a/sys/dev/e1000/e1000_api.h b/sys/dev/e1000/e1000_api.h
index 70aaa15..4c061c0 100644
--- a/sys/dev/e1000/e1000_api.h
+++ b/sys/dev/e1000/e1000_api.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2011, Intel Corporation
+ Copyright (c) 2001-2012, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -49,6 +49,7 @@ extern void e1000_rx_fifo_flush_82575(struct e1000_hw *hw);
extern void e1000_init_function_pointers_vf(struct e1000_hw *hw);
extern void e1000_power_up_fiber_serdes_link(struct e1000_hw *hw);
extern void e1000_shutdown_fiber_serdes_link(struct e1000_hw *hw);
+extern void e1000_init_function_pointers_i210(struct e1000_hw *hw);
s32 e1000_set_mac_type(struct e1000_hw *hw);
s32 e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device);
@@ -118,6 +119,7 @@ s32 e1000_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length);
u32 e1000_translate_register_82542(u32 reg);
+
/*
* TBI_ACCEPT macro definition:
*
diff --git a/sys/dev/e1000/e1000_defines.h b/sys/dev/e1000/e1000_defines.h
index 69ef386..a4a0ed0 100644
--- a/sys/dev/e1000/e1000_defines.h
+++ b/sys/dev/e1000/e1000_defines.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2011, Intel Corporation
+ Copyright (c) 2001-2012, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -1344,6 +1344,16 @@
#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */
#define E1000_EECD_SECVAL_SHIFT 22
#define E1000_EECD_SEC1VAL_VALID_MASK (E1000_EECD_AUTO_RD | E1000_EECD_PRES)
+#define E1000_EECD_FLUPD_I210 0x00800000 /* Update FLASH */
+#define E1000_EECD_FLUDONE_I210 0x04000000 /* Update FLASH done */
+#define E1000_EECD_FLASH_DETECTED_I210 0x00080000 /* FLASH detected */
+#define E1000_FLUDONE_ATTEMPTS 20000
+#define E1000_EERD_EEWR_MAX_COUNT 512 /* buffered EEPROM words rw */
+#define E1000_I210_FIFO_SEL_RX 0x00
+#define E1000_I210_FIFO_SEL_TX_QAV(_i) (0x02 + (_i))
+#define E1000_I210_FIFO_SEL_TX_LEGACY E1000_I210_FIFO_SEL_TX_QAV(0)
+#define E1000_I210_FIFO_SEL_BMC2OS_TX 0x06
+#define E1000_I210_FIFO_SEL_BMC2OS_RX 0x01
#define E1000_NVM_SWDPIN0 0x0001 /* SWDPIN 0 NVM Value */
#define E1000_NVM_LED_LOGIC 0x0020 /* Led Logic Word */
@@ -1361,6 +1371,20 @@
#define NVM_VERSION 0x0005
#define NVM_SERDES_AMPLITUDE 0x0006 /* SERDES output amplitude */
#define NVM_PHY_CLASS_WORD 0x0007
+#define NVM_ETRACK_WORD 0x0042
+#define NVM_COMB_VER_OFF 0x0083
+#define NVM_COMB_VER_PTR 0x003d
+
+#define NVM_MAC_ADDR 0x0000
+#define NVM_SUB_DEV_ID 0x000B
+#define NVM_SUB_VEN_ID 0x000C
+#define NVM_DEV_ID 0x000D
+#define NVM_VEN_ID 0x000E
+#define NVM_INIT_CTRL_2 0x000F
+#define NVM_INIT_CTRL_4 0x0013
+#define NVM_LED_1_CFG 0x001C
+#define NVM_LED_0_2_CFG 0x001F
+
#define NVM_INIT_CONTROL1_REG 0x000A
#define NVM_INIT_CONTROL2_REG 0x000F
#define NVM_SWDEF_PINS_CTRL_PORT_1 0x0010
@@ -1380,12 +1404,12 @@
#define E1000_NVM_CFG_DONE_PORT_2 0x100000 /* ...for third port */
#define E1000_NVM_CFG_DONE_PORT_3 0x200000 /* ...for fourth port */
-#define NVM_82580_LAN_FUNC_OFFSET(a) (a ? (0x40 + (0x40 * a)) : 0)
+#define NVM_82580_LAN_FUNC_OFFSET(a) ((a) ? (0x40 + (0x40 * (a))) : 0)
/* Mask bits for fields in Word 0x24 of the NVM */
#define NVM_WORD24_COM_MDIO 0x0008 /* MDIO interface shared */
#define NVM_WORD24_EXT_MDIO 0x0004 /* MDIO accesses routed extrnl */
-/* Offset of Link Mode bits for 82575 up to Kawela */
+/* Offset of Link Mode bits for 82575/82576 */
#define NVM_WORD24_LNK_MODE_OFFSET 8
/* Offset of Link Mode bits for 82580 up */
#define NVM_WORD24_82580_LNK_MODE_OFFSET 4
@@ -1525,6 +1549,7 @@
#define I82579_E_PHY_ID 0x01540090
#define I82580_I_PHY_ID 0x015403A0
#define I350_I_PHY_ID 0x015403B0
+#define I210_I_PHY_ID 0x01410C00
#define IGP04E1000_E_PHY_ID 0x02A80391
#define M88_VENDOR 0x0141
@@ -1787,6 +1812,8 @@
#define E1000_DMACR_DMAC_LX_MASK 0x30000000
#define E1000_DMACR_DMAC_LX_SHIFT 28
#define E1000_DMACR_DMAC_EN 0x80000000 /* Enable DMA Coalescing */
+/* DMA Coalescing BMC-to-OS Watchdog Enable */
+#define E1000_DMACR_DC_BMC2OSW_EN 0x00008000
/* DMA Coalescing Transmit Threshold */
#define E1000_DMCTXTH_DMCTTHR_MASK 0x00000FFF
@@ -1807,8 +1834,9 @@
/* Lx power decision based on DMA coal */
#define E1000_PCIEMISC_LX_DECISION 0x00000080
-#define E1000_LTRC_EEEMS_EN 0x00000005 /* Enable EEE LTR max send */
#define E1000_RXPBS_SIZE_I210_MASK 0x0000003F /* Rx packet buffer size */
+#define E1000_TXPB0S_SIZE_I210_MASK 0x0000003F /* Tx packet buffer 0 size */
+#define E1000_LTRC_EEEMS_EN 0x00000020 /* Enable EEE LTR max send */
/* Minimum time for 1000BASE-T where no data will be transmit following move out
* of EEE LPI Tx state
*/
@@ -1826,12 +1854,14 @@
#define E1000_LTRMINV_SCALE_1024 2
/* Reg val to set scale to 32768 nsec */
#define E1000_LTRMINV_SCALE_32768 3
+#define E1000_LTRMINV_LSNP_REQ 0x00008000 /* LTR Snoop Requirement */
#define E1000_LTRMAXV_SCALE_MASK 0x00001C00 /* LTR maximum scale */
#define E1000_LTRMAXV_SCALE_SHIFT 10
/* Reg val to set scale to 1024 nsec */
#define E1000_LTRMAXV_SCALE_1024 2
/* Reg val to set scale to 32768 nsec */
#define E1000_LTRMAXV_SCALE_32768 3
+#define E1000_LTRMAXV_LSNP_REQ 0x00008000 /* LTR Snoop Requirement */
#define E1000_DOBFFCTL_OBFFTHR_MASK 0x000000FF /* OBFF threshold */
#define E1000_DOBFFCTL_EXIT_ACT_MASK 0x01000000 /* Exit active CB */
diff --git a/sys/dev/e1000/e1000_hw.h b/sys/dev/e1000/e1000_hw.h
index 16cfa8f..50a5ce2 100644
--- a/sys/dev/e1000/e1000_hw.h
+++ b/sys/dev/e1000/e1000_hw.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2011, Intel Corporation
+ Copyright (c) 2001-2012, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -154,6 +154,13 @@ struct e1000_hw;
#define E1000_DEV_ID_I350_SERDES 0x1523
#define E1000_DEV_ID_I350_SGMII 0x1524
#define E1000_DEV_ID_I350_DA4 0x1546
+#define E1000_DEV_ID_I210_COPPER 0x1533
+#define E1000_DEV_ID_I210_COPPER_OEM1 0x1534
+#define E1000_DEV_ID_I210_COPPER_IT 0x1535
+#define E1000_DEV_ID_I210_FIBER 0x1536
+#define E1000_DEV_ID_I210_SERDES 0x1537
+#define E1000_DEV_ID_I210_SGMII 0x1538
+#define E1000_DEV_ID_I211_COPPER 0x1539
#define E1000_DEV_ID_DH89XXCC_SGMII 0x0438
#define E1000_DEV_ID_DH89XXCC_SERDES 0x043A
#define E1000_DEV_ID_DH89XXCC_BACKPLANE 0x043C
@@ -203,6 +210,8 @@ enum e1000_mac_type {
e1000_82576,
e1000_82580,
e1000_i350,
+ e1000_i210,
+ e1000_i211,
e1000_vfadapt,
e1000_vfadapt_i350,
e1000_num_macs /* List is 1-based, so subtract 1 for TRUE count. */
@@ -248,6 +257,7 @@ enum e1000_phy_type {
e1000_phy_82579,
e1000_phy_82580,
e1000_phy_vf,
+ e1000_phy_i210,
};
enum e1000_bus_type {
@@ -674,6 +684,8 @@ struct e1000_mac_operations {
struct e1000_host_mng_command_header*);
s32 (*mng_enable_host_if)(struct e1000_hw *);
s32 (*wait_autoneg)(struct e1000_hw *);
+ s32 (*acquire_swfw_sync)(struct e1000_hw *, u16);
+ void (*release_swfw_sync)(struct e1000_hw *, u16);
};
/*
@@ -911,13 +923,13 @@ struct e1000_dev_spec_ich8lan {
E1000_MUTEX nvm_mutex;
E1000_MUTEX swflag_mutex;
bool nvm_k1_enabled;
- int eee_disable;
+ bool eee_disable;
};
struct e1000_dev_spec_82575 {
bool sgmii_active;
bool global_device_reset;
- int eee_disable;
+ bool eee_disable;
bool module_plugged;
u32 mtu;
};
@@ -967,6 +979,7 @@ struct e1000_hw {
#include "e1000_80003es2lan.h"
#include "e1000_ich8lan.h"
#include "e1000_82575.h"
+#include "e1000_i210.h"
/* These functions must be implemented by drivers */
void e1000_pci_clear_mwi(struct e1000_hw *hw);
diff --git a/sys/dev/e1000/e1000_i210.c b/sys/dev/e1000/e1000_i210.c
new file mode 100644
index 0000000..f8e8bad
--- /dev/null
+++ b/sys/dev/e1000/e1000_i210.c
@@ -0,0 +1,740 @@
+/******************************************************************************
+
+ Copyright (c) 2001-2012, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+/*$FreeBSD$*/
+
+#include "e1000_api.h"
+
+
+static s32 e1000_acquire_nvm_i210(struct e1000_hw *hw);
+static void e1000_release_nvm_i210(struct e1000_hw *hw);
+static s32 e1000_get_hw_semaphore_i210(struct e1000_hw *hw);
+static void e1000_put_hw_semaphore_i210(struct e1000_hw *hw);
+static s32 e1000_write_nvm_srwr(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data);
+static s32 e1000_pool_flash_update_done_i210(struct e1000_hw *hw);
+static s32 e1000_valid_led_default_i210(struct e1000_hw *hw, u16 *data);
+static s32 e1000_read_nvm_i211(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data);
+
+/**
+ * e1000_acquire_nvm_i210 - Request for access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the necessary semaphores for exclusive access to the EEPROM.
+ * Set the EEPROM access request bit and wait for EEPROM access grant bit.
+ * Return successful if access grant bit set, else clear the request for
+ * EEPROM access and return -E1000_ERR_NVM (-1).
+ **/
+static s32 e1000_acquire_nvm_i210(struct e1000_hw *hw)
+{
+ s32 ret_val;
+
+ DEBUGFUNC("e1000_acquire_nvm_i210");
+
+ ret_val = e1000_acquire_swfw_sync_i210(hw, E1000_SWFW_EEP_SM);
+
+ return ret_val;
+}
+
+/**
+ * e1000_release_nvm_i210 - Release exclusive access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Stop any current commands to the EEPROM and clear the EEPROM request bit,
+ * then release the semaphores acquired.
+ **/
+static void e1000_release_nvm_i210(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_release_nvm_i210");
+
+ e1000_release_swfw_sync_i210(hw, E1000_SWFW_EEP_SM);
+}
+
+/**
+ * e1000_acquire_swfw_sync_i210 - Acquire SW/FW semaphore
+ * @hw: pointer to the HW structure
+ * @mask: specifies which semaphore to acquire
+ *
+ * Acquire the SW/FW semaphore to access the PHY or NVM. The mask
+ * will also specify which port we're acquiring the lock for.
+ **/
+s32 e1000_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask)
+{
+ u32 swfw_sync;
+ u32 swmask = mask;
+ u32 fwmask = mask << 16;
+ s32 ret_val = E1000_SUCCESS;
+ s32 i = 0, timeout = 200; /* FIXME: find real value to use here */
+
+ DEBUGFUNC("e1000_acquire_swfw_sync_i210");
+
+ while (i < timeout) {
+ if (e1000_get_hw_semaphore_i210(hw)) {
+ ret_val = -E1000_ERR_SWFW_SYNC;
+ goto out;
+ }
+
+ swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC);
+ if (!(swfw_sync & fwmask))
+ break;
+
+ /*
+ * Firmware currently using resource (fwmask)
+ */
+ e1000_put_hw_semaphore_i210(hw);
+ msec_delay_irq(5);
+ i++;
+ }
+
+ if (i == timeout) {
+ DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n");
+ ret_val = -E1000_ERR_SWFW_SYNC;
+ goto out;
+ }
+
+ swfw_sync |= swmask;
+ E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync);
+
+ e1000_put_hw_semaphore_i210(hw);
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_release_swfw_sync_i210 - Release SW/FW semaphore
+ * @hw: pointer to the HW structure
+ * @mask: specifies which semaphore to acquire
+ *
+ * Release the SW/FW semaphore used to access the PHY or NVM. The mask
+ * will also specify which port we're releasing the lock for.
+ **/
+void e1000_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask)
+{
+ u32 swfw_sync;
+
+ DEBUGFUNC("e1000_release_swfw_sync_i210");
+
+ while (e1000_get_hw_semaphore_i210(hw) != E1000_SUCCESS)
+ ; /* Empty */
+
+ swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC);
+ swfw_sync &= ~mask;
+ E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync);
+
+ e1000_put_hw_semaphore_i210(hw);
+}
+
+/**
+ * e1000_get_hw_semaphore_i210 - Acquire hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the HW semaphore to access the PHY or NVM
+ **/
+static s32 e1000_get_hw_semaphore_i210(struct e1000_hw *hw)
+{
+ u32 swsm;
+ s32 ret_val = E1000_SUCCESS;
+ s32 timeout = hw->nvm.word_size + 1;
+ s32 i = 0;
+
+ DEBUGFUNC("e1000_get_hw_semaphore_i210");
+
+ /* Get the FW semaphore. */
+ for (i = 0; i < timeout; i++) {
+ swsm = E1000_READ_REG(hw, E1000_SWSM);
+ E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI);
+
+ /* Semaphore acquired if bit latched */
+ if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI)
+ break;
+
+ usec_delay(50);
+ }
+
+ if (i == timeout) {
+ /* Release semaphores */
+ e1000_put_hw_semaphore_generic(hw);
+ DEBUGOUT("Driver can't access the NVM\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_put_hw_semaphore_i210 - Release hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Release hardware semaphore used to access the PHY or NVM
+ **/
+static void e1000_put_hw_semaphore_i210(struct e1000_hw *hw)
+{
+ u32 swsm;
+
+ DEBUGFUNC("e1000_put_hw_semaphore_i210");
+
+ swsm = E1000_READ_REG(hw, E1000_SWSM);
+
+ swsm &= ~E1000_SWSM_SWESMBI;
+
+ E1000_WRITE_REG(hw, E1000_SWSM, swsm);
+}
+
+/**
+ * e1000_read_nvm_srrd_i210 - Reads Shadow Ram using EERD register
+ * @hw: pointer to the HW structure
+ * @offset: offset of word in the Shadow Ram to read
+ * @words: number of words to read
+ * @data: word read from the Shadow Ram
+ *
+ * Reads a 16 bit word from the Shadow Ram using the EERD register.
+ * Uses necessary synchronization semaphores.
+ **/
+s32 e1000_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data)
+{
+ s32 status = E1000_SUCCESS;
+ u16 i, count;
+
+ DEBUGFUNC("e1000_read_nvm_srrd_i210");
+
+ /* We cannot hold synchronization semaphores for too long,
+ * because of forceful takeover procedure. However it is more efficient
+ * to read in bursts than synchronizing access for each word. */
+ for (i = 0; i < words; i += E1000_EERD_EEWR_MAX_COUNT) {
+ count = (words - i) / E1000_EERD_EEWR_MAX_COUNT > 0 ?
+ E1000_EERD_EEWR_MAX_COUNT : (words - i);
+ if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) {
+ status = e1000_read_nvm_eerd(hw, offset, count,
+ data + i);
+ hw->nvm.ops.release(hw);
+ } else {
+ status = E1000_ERR_SWFW_SYNC;
+ }
+
+ if (status != E1000_SUCCESS)
+ break;
+ }
+
+ return status;
+}
+
+/**
+ * e1000_write_nvm_srwr_i210 - Write to Shadow RAM using EEWR
+ * @hw: pointer to the HW structure
+ * @offset: offset within the Shadow RAM to be written to
+ * @words: number of words to write
+ * @data: 16 bit word(s) to be written to the Shadow RAM
+ *
+ * Writes data to Shadow RAM at offset using EEWR register.
+ *
+ * If e1000_update_nvm_checksum is not called after this function , the
+ * data will not be committed to FLASH and also Shadow RAM will most likely
+ * contain an invalid checksum.
+ *
+ * If error code is returned, data and Shadow RAM may be inconsistent - buffer
+ * partially written.
+ **/
+s32 e1000_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data)
+{
+ s32 status = E1000_SUCCESS;
+ u16 i, count;
+
+ DEBUGFUNC("e1000_write_nvm_srwr_i210");
+
+ /* We cannot hold synchronization semaphores for too long,
+ * because of forceful takeover procedure. However it is more efficient
+ * to write in bursts than synchronizing access for each word. */
+ for (i = 0; i < words; i += E1000_EERD_EEWR_MAX_COUNT) {
+ count = (words - i) / E1000_EERD_EEWR_MAX_COUNT > 0 ?
+ E1000_EERD_EEWR_MAX_COUNT : (words - i);
+ if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) {
+ status = e1000_write_nvm_srwr(hw, offset, count,
+ data + i);
+ hw->nvm.ops.release(hw);
+ } else {
+ status = E1000_ERR_SWFW_SYNC;
+ }
+
+ if (status != E1000_SUCCESS)
+ break;
+ }
+
+ return status;
+}
+
+/**
+ * e1000_write_nvm_srwr - Write to Shadow Ram using EEWR
+ * @hw: pointer to the HW structure
+ * @offset: offset within the Shadow Ram to be written to
+ * @words: number of words to write
+ * @data: 16 bit word(s) to be written to the Shadow Ram
+ *
+ * Writes data to Shadow Ram at offset using EEWR register.
+ *
+ * If e1000_update_nvm_checksum is not called after this function , the
+ * Shadow Ram will most likely contain an invalid checksum.
+ **/
+static s32 e1000_write_nvm_srwr(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ u32 i, k, eewr = 0;
+ u32 attempts = 100000;
+ s32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_write_nvm_srwr");
+
+ /*
+ * A check for invalid values: offset too large, too many words,
+ * too many words for the offset, and not enough words.
+ */
+ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+ (words == 0)) {
+ DEBUGOUT("nvm parameter(s) out of bounds\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ for (i = 0; i < words; i++) {
+ eewr = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) |
+ (data[i] << E1000_NVM_RW_REG_DATA) |
+ E1000_NVM_RW_REG_START;
+
+ E1000_WRITE_REG(hw, E1000_SRWR, eewr);
+
+ for (k = 0; k < attempts; k++) {
+ if (E1000_NVM_RW_REG_DONE &
+ E1000_READ_REG(hw, E1000_SRWR)) {
+ ret_val = E1000_SUCCESS;
+ break;
+ }
+ usec_delay(5);
+ }
+
+ if (ret_val != E1000_SUCCESS) {
+ DEBUGOUT("Shadow RAM write EEWR timed out\n");
+ break;
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_read_nvm_i211 - Read NVM wrapper function for I211
+ * @hw: pointer to the HW structure
+ * @address: the word address (aka eeprom offset) to read
+ * @data: pointer to the data read
+ *
+ * Wrapper function to return data formerly found in the NVM.
+ **/
+static s32 e1000_read_nvm_i211(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data)
+{
+ s32 ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_read_nvm_i211");
+
+ /* Only the MAC addr is required to be present in the iNVM */
+ switch (offset) {
+ case NVM_MAC_ADDR:
+ ret_val = e1000_read_invm_i211(hw, (u8)offset, &data[0]);
+ ret_val |= e1000_read_invm_i211(hw, (u8)offset+1, &data[1]);
+ ret_val |= e1000_read_invm_i211(hw, (u8)offset+2, &data[2]);
+ if (ret_val != E1000_SUCCESS)
+ DEBUGOUT("MAC Addr not found in iNVM\n");
+ break;
+ case NVM_ID_LED_SETTINGS:
+ case NVM_INIT_CTRL_2:
+ case NVM_INIT_CTRL_4:
+ case NVM_LED_1_CFG:
+ case NVM_LED_0_2_CFG:
+ e1000_read_invm_i211(hw, (u8)offset, data);
+ break;
+ case NVM_COMPAT:
+ *data = ID_LED_DEFAULT_I210;
+ break;
+ case NVM_SUB_DEV_ID:
+ *data = hw->subsystem_device_id;
+ break;
+ case NVM_SUB_VEN_ID:
+ *data = hw->subsystem_vendor_id;
+ break;
+ case NVM_DEV_ID:
+ *data = hw->device_id;
+ break;
+ case NVM_VEN_ID:
+ *data = hw->vendor_id;
+ break;
+ default:
+ DEBUGOUT1("NVM word 0x%02x is not mapped.\n", offset);
+ *data = NVM_RESERVED_WORD;
+ break;
+ }
+ return ret_val;
+}
+
+/**
+ * e1000_read_invm_i211 - Reads OTP
+ * @hw: pointer to the HW structure
+ * @address: the word address (aka eeprom offset) to read
+ * @data: pointer to the data read
+ *
+ * Reads 16-bit words from the OTP. Return error when the word is not
+ * stored in OTP.
+ **/
+s32 e1000_read_invm_i211(struct e1000_hw *hw, u8 address, u16 *data)
+{
+ s32 status = -E1000_ERR_INVM_VALUE_NOT_FOUND;
+ u32 invm_dword;
+ u16 i;
+ u8 record_type, word_address;
+
+ DEBUGFUNC("e1000_read_invm_i211");
+
+ for (i = 0; i < E1000_INVM_SIZE; i++) {
+ invm_dword = E1000_READ_REG(hw, E1000_INVM_DATA_REG(i));
+ /* Get record type */
+ record_type = INVM_DWORD_TO_RECORD_TYPE(invm_dword);
+ if (record_type == E1000_INVM_UNINITIALIZED_STRUCTURE)
+ break;
+ if (record_type == E1000_INVM_CSR_AUTOLOAD_STRUCTURE)
+ i += E1000_INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS;
+ if (record_type == E1000_INVM_RSA_KEY_SHA256_STRUCTURE)
+ i += E1000_INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS;
+ if (record_type == E1000_INVM_WORD_AUTOLOAD_STRUCTURE) {
+ word_address = INVM_DWORD_TO_WORD_ADDRESS(invm_dword);
+ if (word_address == address) {
+ *data = INVM_DWORD_TO_WORD_DATA(invm_dword);
+ DEBUGOUT2("Read INVM Word 0x%02x = %x",
+ address, *data);
+ status = E1000_SUCCESS;
+ break;
+ }
+ }
+ }
+ if (status != E1000_SUCCESS)
+ DEBUGOUT1("Requested word 0x%02x not found in OTP\n", address);
+ return status;
+}
+
+/**
+ * e1000_validate_nvm_checksum_i210 - Validate EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ * and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ **/
+s32 e1000_validate_nvm_checksum_i210(struct e1000_hw *hw)
+{
+ s32 status = E1000_SUCCESS;
+ s32 (*read_op_ptr)(struct e1000_hw *, u16, u16, u16 *);
+
+ DEBUGFUNC("e1000_validate_nvm_checksum_i210");
+
+ if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) {
+
+ /*
+ * Replace the read function with semaphore grabbing with
+ * the one that skips this for a while.
+ * We have semaphore taken already here.
+ */
+ read_op_ptr = hw->nvm.ops.read;
+ hw->nvm.ops.read = e1000_read_nvm_eerd;
+
+ status = e1000_validate_nvm_checksum_generic(hw);
+
+ /* Revert original read operation. */
+ hw->nvm.ops.read = read_op_ptr;
+
+ hw->nvm.ops.release(hw);
+ } else {
+ status = E1000_ERR_SWFW_SYNC;
+ }
+
+ return status;
+}
+
+
+/**
+ * e1000_update_nvm_checksum_i210 - Update EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ * up to the checksum. Then calculates the EEPROM checksum and writes the
+ * value to the EEPROM. Next commit EEPROM data onto the Flash.
+ **/
+s32 e1000_update_nvm_checksum_i210(struct e1000_hw *hw)
+{
+ s32 ret_val = E1000_SUCCESS;
+ u16 checksum = 0;
+ u16 i, nvm_data;
+
+ DEBUGFUNC("e1000_update_nvm_checksum_i210");
+
+ /*
+ * Read the first word from the EEPROM. If this times out or fails, do
+ * not continue or we could be in for a very long wait while every
+ * EEPROM read fails
+ */
+ ret_val = e1000_read_nvm_eerd(hw, 0, 1, &nvm_data);
+ if (ret_val != E1000_SUCCESS) {
+ DEBUGOUT("EEPROM read failed\n");
+ goto out;
+ }
+
+ if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) {
+ /*
+ * Do not use hw->nvm.ops.write, hw->nvm.ops.read
+ * because we do not want to take the synchronization
+ * semaphores twice here.
+ */
+
+ for (i = 0; i < NVM_CHECKSUM_REG; i++) {
+ ret_val = e1000_read_nvm_eerd(hw, i, 1, &nvm_data);
+ if (ret_val) {
+ hw->nvm.ops.release(hw);
+ DEBUGOUT("NVM Read Error while updating checksum.\n");
+ goto out;
+ }
+ checksum += nvm_data;
+ }
+ checksum = (u16) NVM_SUM - checksum;
+ ret_val = e1000_write_nvm_srwr(hw, NVM_CHECKSUM_REG, 1,
+ &checksum);
+ if (ret_val != E1000_SUCCESS) {
+ hw->nvm.ops.release(hw);
+ DEBUGOUT("NVM Write Error while updating checksum.\n");
+ goto out;
+ }
+
+ hw->nvm.ops.release(hw);
+
+ ret_val = e1000_update_flash_i210(hw);
+ } else {
+ ret_val = E1000_ERR_SWFW_SYNC;
+ }
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_get_flash_presence_i210 - Check if flash device is detected.
+ * @hw: pointer to the HW structure
+ *
+ **/
+static bool e1000_get_flash_presence_i210(struct e1000_hw *hw)
+{
+ u32 eec = 0;
+ bool ret_val = FALSE;
+
+ DEBUGFUNC("e1000_get_flash_presence_i210");
+
+ eec = E1000_READ_REG(hw, E1000_EECD);
+
+ if (eec & E1000_EECD_FLASH_DETECTED_I210)
+ ret_val = TRUE;
+
+ return ret_val;
+}
+
+/**
+ * e1000_update_flash_i210 - Commit EEPROM to the flash
+ * @hw: pointer to the HW structure
+ *
+ **/
+s32 e1000_update_flash_i210(struct e1000_hw *hw)
+{
+ s32 ret_val = E1000_SUCCESS;
+ u32 flup;
+
+ DEBUGFUNC("e1000_update_flash_i210");
+
+ ret_val = e1000_pool_flash_update_done_i210(hw);
+ if (ret_val == -E1000_ERR_NVM) {
+ DEBUGOUT("Flash update time out\n");
+ goto out;
+ }
+
+ flup = E1000_READ_REG(hw, E1000_EECD) | E1000_EECD_FLUPD_I210;
+ E1000_WRITE_REG(hw, E1000_EECD, flup);
+
+ ret_val = e1000_pool_flash_update_done_i210(hw);
+ if (ret_val == E1000_SUCCESS)
+ DEBUGOUT("Flash update complete\n");
+ else
+ DEBUGOUT("Flash update time out\n");
+
+out:
+ return ret_val;
+}
+
+/**
+ * e1000_pool_flash_update_done_i210 - Pool FLUDONE status.
+ * @hw: pointer to the HW structure
+ *
+ **/
+s32 e1000_pool_flash_update_done_i210(struct e1000_hw *hw)
+{
+ s32 ret_val = -E1000_ERR_NVM;
+ u32 i, reg;
+
+ DEBUGFUNC("e1000_pool_flash_update_done_i210");
+
+ for (i = 0; i < E1000_FLUDONE_ATTEMPTS; i++) {
+ reg = E1000_READ_REG(hw, E1000_EECD);
+ if (reg & E1000_EECD_FLUDONE_I210) {
+ ret_val = E1000_SUCCESS;
+ break;
+ }
+ usec_delay(5);
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_init_nvm_params_i210 - Initialize i210 NVM function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Initialize the i210 NVM parameters and function pointers.
+ **/
+static s32 e1000_init_nvm_params_i210(struct e1000_hw *hw)
+{
+ s32 ret_val = E1000_SUCCESS;
+ struct e1000_nvm_info *nvm = &hw->nvm;
+
+ DEBUGFUNC("e1000_init_nvm_params_i210");
+
+ ret_val = e1000_init_nvm_params_82575(hw);
+
+ nvm->ops.acquire = e1000_acquire_nvm_i210;
+ nvm->ops.release = e1000_release_nvm_i210;
+ nvm->ops.read = e1000_read_nvm_srrd_i210;
+ nvm->ops.write = e1000_write_nvm_srwr_i210;
+ nvm->ops.valid_led_default = e1000_valid_led_default_i210;
+ nvm->ops.validate = e1000_validate_nvm_checksum_i210;
+ nvm->ops.update = e1000_update_nvm_checksum_i210;
+
+ return ret_val;
+}
+
+/**
+ * e1000_init_nvm_params_i211 - Initialize i211 NVM function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Initialize the NVM parameters and function pointers for i211.
+ **/
+static s32 e1000_init_nvm_params_i211(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+
+ DEBUGFUNC("e1000_init_nvm_params_i211");
+
+ nvm->ops.acquire = e1000_acquire_nvm_i210;
+ nvm->ops.release = e1000_release_nvm_i210;
+ nvm->ops.read = e1000_read_nvm_i211;
+ nvm->ops.valid_led_default = e1000_valid_led_default_i210;
+ nvm->ops.write = e1000_null_write_nvm;
+ nvm->ops.validate = e1000_null_ops_generic;
+ nvm->ops.update = e1000_null_ops_generic;
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_init_function_pointers_i210 - Init func ptrs.
+ * @hw: pointer to the HW structure
+ *
+ * Called to initialize all function pointers and parameters.
+ **/
+void e1000_init_function_pointers_i210(struct e1000_hw *hw)
+{
+ e1000_init_function_pointers_82575(hw);
+
+ switch (hw->mac.type) {
+ case e1000_i210:
+ if (e1000_get_flash_presence_i210(hw))
+ hw->nvm.ops.init_params = e1000_init_nvm_params_i210;
+ else
+ hw->nvm.ops.init_params = e1000_init_nvm_params_i211;
+ break;
+ case e1000_i211:
+ hw->nvm.ops.init_params = e1000_init_nvm_params_i211;
+ break;
+ default:
+ break;
+ }
+ return;
+}
+
+/**
+ * e1000_valid_led_default_i210 - Verify a valid default LED config
+ * @hw: pointer to the HW structure
+ * @data: pointer to the NVM (EEPROM)
+ *
+ * Read the EEPROM for the current default LED configuration. If the
+ * LED configuration is not valid, set to a valid LED configuration.
+ **/
+static s32 e1000_valid_led_default_i210(struct e1000_hw *hw, u16 *data)
+{
+ s32 ret_val;
+
+ DEBUGFUNC("e1000_valid_led_default_i210");
+
+ ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ goto out;
+ }
+
+ if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) {
+ switch (hw->phy.media_type) {
+ case e1000_media_type_internal_serdes:
+ *data = ID_LED_DEFAULT_I210_SERDES;
+ break;
+ case e1000_media_type_copper:
+ default:
+ *data = ID_LED_DEFAULT_I210;
+ break;
+ }
+ }
+out:
+ return ret_val;
+}
diff --git a/sys/dev/e1000/e1000_i210.h b/sys/dev/e1000/e1000_i210.h
new file mode 100644
index 0000000..a0cd935
--- /dev/null
+++ b/sys/dev/e1000/e1000_i210.h
@@ -0,0 +1,80 @@
+/******************************************************************************
+
+ Copyright (c) 2001-2012, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+/*$FreeBSD$*/
+
+#ifndef _E1000_I210_H_
+#define _E1000_I210_H_
+
+s32 e1000_update_flash_i210(struct e1000_hw *hw);
+s32 e1000_update_nvm_checksum_i210(struct e1000_hw *hw);
+s32 e1000_validate_nvm_checksum_i210(struct e1000_hw *hw);
+s32 e1000_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset,
+ u16 words, u16 *data);
+s32 e1000_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset,
+ u16 words, u16 *data);
+s32 e1000_read_invm_i211(struct e1000_hw *hw, u8 address, u16 *data);
+s32 e1000_check_for_copper_link_i210(struct e1000_hw *hw);
+s32 e1000_set_ltr_i210(struct e1000_hw *hw, bool link);
+s32 e1000_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask);
+void e1000_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask);
+
+#define E1000_STM_OPCODE 0xDB00
+#define E1000_EEPROM_FLASH_SIZE_WORD 0x11
+
+#define INVM_DWORD_TO_RECORD_TYPE(invm_dword) \
+ (u8)((invm_dword) & 0x7)
+#define INVM_DWORD_TO_WORD_ADDRESS(invm_dword) \
+ (u8)(((invm_dword) & 0x0000FE00) >> 9)
+#define INVM_DWORD_TO_WORD_DATA(invm_dword) \
+ (u16)(((invm_dword) & 0xFFFF0000) >> 16)
+
+enum E1000_INVM_STRUCTURE_TYPE {
+ E1000_INVM_UNINITIALIZED_STRUCTURE = 0x00,
+ E1000_INVM_WORD_AUTOLOAD_STRUCTURE = 0x01,
+ E1000_INVM_CSR_AUTOLOAD_STRUCTURE = 0x02,
+ E1000_INVM_PHY_REGISTER_AUTOLOAD_STRUCTURE = 0x03,
+ E1000_INVM_RSA_KEY_SHA256_STRUCTURE = 0x04,
+ E1000_INVM_INVALIDATED_STRUCTURE = 0x0F,
+};
+
+#define E1000_INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS 8
+#define E1000_INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS 1
+
+#define ID_LED_DEFAULT_I210 ((ID_LED_OFF1_ON2 << 8) | \
+ (ID_LED_DEF1_DEF2 << 4) | \
+ (ID_LED_OFF1_OFF2))
+#define ID_LED_DEFAULT_I210_SERDES ((ID_LED_DEF1_DEF2 << 8) | \
+ (ID_LED_DEF1_DEF2 << 4) | \
+ (ID_LED_DEF1_DEF2))
+
+#endif
diff --git a/sys/dev/e1000/e1000_ich8lan.c b/sys/dev/e1000/e1000_ich8lan.c
index aa4802c..98aefc4 100644
--- a/sys/dev/e1000/e1000_ich8lan.c
+++ b/sys/dev/e1000/e1000_ich8lan.c
@@ -738,7 +738,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
* of MAC speed/duplex configuration. So we only need to
* configure Collision Distance in the MAC.
*/
- e1000_config_collision_dist_generic(hw);
+ hw->mac.ops.config_collision_dist(hw);
/*
* Configure Flow Control now that Auto-Neg has completed.
diff --git a/sys/dev/e1000/e1000_mac.c b/sys/dev/e1000/e1000_mac.c
index 4fc2a7c..95d6873 100644
--- a/sys/dev/e1000/e1000_mac.c
+++ b/sys/dev/e1000/e1000_mac.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2011, Intel Corporation
+ Copyright (c) 2001-2012, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -36,6 +36,8 @@
static s32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw);
static void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw);
+static void e1000_config_collision_dist_generic(struct e1000_hw *hw);
+static void e1000_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index);
/**
* e1000_init_mac_ops_generic - Initialize MAC function pointers
@@ -395,30 +397,30 @@ s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw)
ret_val = hw->nvm.ops.read(hw, NVM_COMPAT, 1, &nvm_data);
if (ret_val)
- goto out;
+ return ret_val;
/* not supported on older hardware or 82573 */
if ((hw->mac.type < e1000_82571) || (hw->mac.type == e1000_82573))
- goto out;
+ return E1000_SUCCESS;
/*
* Alternate MAC address is handled by the option ROM for 82580
* and newer. SW support not required.
*/
if (hw->mac.type >= e1000_82580)
- goto out;
+ return E1000_SUCCESS;
ret_val = hw->nvm.ops.read(hw, NVM_ALT_MAC_ADDR_PTR, 1,
&nvm_alt_mac_addr_offset);
if (ret_val) {
DEBUGOUT("NVM Read Error\n");
- goto out;
+ return ret_val;
}
if ((nvm_alt_mac_addr_offset == 0xFFFF) ||
(nvm_alt_mac_addr_offset == 0x0000))
/* There is no Alternate MAC Address */
- goto out;
+ return E1000_SUCCESS;
if (hw->bus.func == E1000_FUNC_1)
nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1;
@@ -432,7 +434,7 @@ s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw)
ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
if (ret_val) {
DEBUGOUT("NVM Read Error\n");
- goto out;
+ return ret_val;
}
alt_mac_addr[i] = (u8)(nvm_data & 0xFF);
@@ -442,7 +444,7 @@ s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw)
/* if multicast bit is set, the alternate address will not be used */
if (alt_mac_addr[0] & 0x01) {
DEBUGOUT("Ignoring Alternate Mac Address with MC bit set\n");
- goto out;
+ return E1000_SUCCESS;
}
/*
@@ -452,8 +454,7 @@ s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw)
*/
hw->mac.ops.rar_set(hw, alt_mac_addr, 0);
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -465,7 +466,7 @@ out:
* Sets the receive address array register at index to the address passed
* in by addr.
**/
-void e1000_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index)
+static void e1000_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index)
{
u32 rar_low, rar_high;
@@ -496,43 +497,6 @@ void e1000_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index)
}
/**
- * e1000_update_mc_addr_list_generic - Update Multicast addresses
- * @hw: pointer to the HW structure
- * @mc_addr_list: array of multicast addresses to program
- * @mc_addr_count: number of multicast addresses to program
- *
- * Updates entire Multicast Table Array.
- * The caller must have a packed mc_addr_list of multicast addresses.
- **/
-void e1000_update_mc_addr_list_generic(struct e1000_hw *hw,
- u8 *mc_addr_list, u32 mc_addr_count)
-{
- u32 hash_value, hash_bit, hash_reg;
- int i;
-
- DEBUGFUNC("e1000_update_mc_addr_list_generic");
-
- /* clear mta_shadow */
- memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));
-
- /* update mta_shadow from mc_addr_list */
- for (i = 0; (u32) i < mc_addr_count; i++) {
- hash_value = e1000_hash_mc_addr_generic(hw, mc_addr_list);
-
- hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
- hash_bit = hash_value & 0x1F;
-
- hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit);
- mc_addr_list += (ETH_ADDR_LEN);
- }
-
- /* replace the entire MTA table */
- for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
- E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, hw->mac.mta_shadow[i]);
- E1000_WRITE_FLUSH(hw);
-}
-
-/**
* e1000_hash_mc_addr_generic - Generate a multicast hash value
* @hw: pointer to the HW structure
* @mc_addr: pointer to a multicast address
@@ -605,6 +569,43 @@ u32 e1000_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr)
}
/**
+ * e1000_update_mc_addr_list_generic - Update Multicast addresses
+ * @hw: pointer to the HW structure
+ * @mc_addr_list: array of multicast addresses to program
+ * @mc_addr_count: number of multicast addresses to program
+ *
+ * Updates entire Multicast Table Array.
+ * The caller must have a packed mc_addr_list of multicast addresses.
+ **/
+void e1000_update_mc_addr_list_generic(struct e1000_hw *hw,
+ u8 *mc_addr_list, u32 mc_addr_count)
+{
+ u32 hash_value, hash_bit, hash_reg;
+ int i;
+
+ DEBUGFUNC("e1000_update_mc_addr_list_generic");
+
+ /* clear mta_shadow */
+ memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));
+
+ /* update mta_shadow from mc_addr_list */
+ for (i = 0; (u32) i < mc_addr_count; i++) {
+ hash_value = e1000_hash_mc_addr_generic(hw, mc_addr_list);
+
+ hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
+ hash_bit = hash_value & 0x1F;
+
+ hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit);
+ mc_addr_list += (ETH_ADDR_LEN);
+ }
+
+ /* replace the entire MTA table */
+ for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, hw->mac.mta_shadow[i]);
+ E1000_WRITE_FLUSH(hw);
+}
+
+/**
* e1000_pcix_mmrbc_workaround_generic - Fix incorrect MMRBC value
* @hw: pointer to the HW structure
*
@@ -712,10 +713,8 @@ s32 e1000_check_for_copper_link_generic(struct e1000_hw *hw)
* get_link_status flag is set upon receiving a Link Status
* Change or Rx Sequence Error interrupt.
*/
- if (!mac->get_link_status) {
- ret_val = E1000_SUCCESS;
- goto out;
- }
+ if (!mac->get_link_status)
+ return E1000_SUCCESS;
/*
* First we want to see if the MII Status Register reports
@@ -724,10 +723,10 @@ s32 e1000_check_for_copper_link_generic(struct e1000_hw *hw)
*/
ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
if (ret_val)
- goto out;
+ return ret_val;
if (!link)
- goto out; /* No link detected */
+ return E1000_SUCCESS; /* No link detected */
mac->get_link_status = FALSE;
@@ -741,10 +740,8 @@ s32 e1000_check_for_copper_link_generic(struct e1000_hw *hw)
* If we are forcing speed/duplex, then we simply return since
* we have already determined whether we have link or not.
*/
- if (!mac->autoneg) {
- ret_val = -E1000_ERR_CONFIG;
- goto out;
- }
+ if (!mac->autoneg)
+ return -E1000_ERR_CONFIG;
/*
* Auto-Neg is enabled. Auto Speed Detection takes care
@@ -763,7 +760,6 @@ s32 e1000_check_for_copper_link_generic(struct e1000_hw *hw)
if (ret_val)
DEBUGOUT("Error configuring flow control\n");
-out:
return ret_val;
}
@@ -780,7 +776,7 @@ s32 e1000_check_for_fiber_link_generic(struct e1000_hw *hw)
u32 rxcw;
u32 ctrl;
u32 status;
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
DEBUGFUNC("e1000_check_for_fiber_link_generic");
@@ -797,11 +793,11 @@ s32 e1000_check_for_fiber_link_generic(struct e1000_hw *hw)
* was just plugged in. The autoneg_failed flag does this.
*/
/* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
- if ((ctrl & E1000_CTRL_SWDPIN1) && (!(status & E1000_STATUS_LU)) &&
- (!(rxcw & E1000_RXCW_C))) {
- if (mac->autoneg_failed == 0) {
- mac->autoneg_failed = 1;
- goto out;
+ if ((ctrl & E1000_CTRL_SWDPIN1) && !(status & E1000_STATUS_LU) &&
+ !(rxcw & E1000_RXCW_C)) {
+ if (!mac->autoneg_failed) {
+ mac->autoneg_failed = TRUE;
+ return E1000_SUCCESS;
}
DEBUGOUT("NOT Rx'ing /C/, disable AutoNeg and force link.\n");
@@ -817,7 +813,7 @@ s32 e1000_check_for_fiber_link_generic(struct e1000_hw *hw)
ret_val = e1000_config_fc_after_link_up_generic(hw);
if (ret_val) {
DEBUGOUT("Error configuring flow control\n");
- goto out;
+ return ret_val;
}
} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
/*
@@ -833,8 +829,7 @@ s32 e1000_check_for_fiber_link_generic(struct e1000_hw *hw)
mac->serdes_has_link = TRUE;
}
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -850,7 +845,7 @@ s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
u32 rxcw;
u32 ctrl;
u32 status;
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
DEBUGFUNC("e1000_check_for_serdes_link_generic");
@@ -866,10 +861,10 @@ s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
* time to complete.
*/
/* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
- if ((!(status & E1000_STATUS_LU)) && (!(rxcw & E1000_RXCW_C))) {
- if (mac->autoneg_failed == 0) {
- mac->autoneg_failed = 1;
- goto out;
+ if (!(status & E1000_STATUS_LU) && !(rxcw & E1000_RXCW_C)) {
+ if (!mac->autoneg_failed) {
+ mac->autoneg_failed = TRUE;
+ return E1000_SUCCESS;
}
DEBUGOUT("NOT Rx'ing /C/, disable AutoNeg and force link.\n");
@@ -885,7 +880,7 @@ s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
ret_val = e1000_config_fc_after_link_up_generic(hw);
if (ret_val) {
DEBUGOUT("Error configuring flow control\n");
- goto out;
+ return ret_val;
}
} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
/*
@@ -943,8 +938,48 @@ s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
}
}
-out:
- return ret_val;
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_set_default_fc_generic - Set flow control default values
+ * @hw: pointer to the HW structure
+ *
+ * Read the EEPROM for the default values for flow control and store the
+ * values.
+ **/
+s32 e1000_set_default_fc_generic(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ u16 nvm_data;
+
+ DEBUGFUNC("e1000_set_default_fc_generic");
+
+ /*
+ * Read and store word 0x0F of the EEPROM. This word contains bits
+ * that determine the hardware's default PAUSE (flow control) mode,
+ * a bit that determines whether the HW defaults to enabling or
+ * disabling auto-negotiation, and the direction of the
+ * SW defined pins. If there is no SW over-ride of the flow
+ * control setting, then the variable hw->fc will
+ * be initialized based on a value in the EEPROM.
+ */
+ ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data);
+
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ return ret_val;
+ }
+
+ if (!(nvm_data & NVM_WORD0F_PAUSE_MASK))
+ hw->fc.requested_mode = e1000_fc_none;
+ else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) ==
+ NVM_WORD0F_ASM_DIR)
+ hw->fc.requested_mode = e1000_fc_tx_pause;
+ else
+ hw->fc.requested_mode = e1000_fc_full;
+
+ return E1000_SUCCESS;
}
/**
@@ -959,7 +994,7 @@ out:
**/
s32 e1000_setup_link_generic(struct e1000_hw *hw)
{
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
DEBUGFUNC("e1000_setup_link_generic");
@@ -967,8 +1002,8 @@ s32 e1000_setup_link_generic(struct e1000_hw *hw)
* In the case of the phy reset being blocked, we already have a link.
* We do not need to set it up again.
*/
- if (e1000_check_reset_block(hw))
- goto out;
+ if (hw->phy.ops.check_reset_block && hw->phy.ops.check_reset_block(hw))
+ return E1000_SUCCESS;
/*
* If requested flow control is set to default, set flow control
@@ -977,7 +1012,7 @@ s32 e1000_setup_link_generic(struct e1000_hw *hw)
if (hw->fc.requested_mode == e1000_fc_default) {
ret_val = e1000_set_default_fc_generic(hw);
if (ret_val)
- goto out;
+ return ret_val;
}
/*
@@ -992,7 +1027,7 @@ s32 e1000_setup_link_generic(struct e1000_hw *hw)
/* Call the necessary media_type subroutine to configure the link. */
ret_val = hw->mac.ops.setup_physical_interface(hw);
if (ret_val)
- goto out;
+ return ret_val;
/*
* Initialize the flow control address, type, and PAUSE timer
@@ -1007,87 +1042,80 @@ s32 e1000_setup_link_generic(struct e1000_hw *hw)
E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
- ret_val = e1000_set_fc_watermarks_generic(hw);
-
-out:
- return ret_val;
+ return e1000_set_fc_watermarks_generic(hw);
}
/**
- * e1000_setup_fiber_serdes_link_generic - Setup link for fiber/serdes
+ * e1000_commit_fc_settings_generic - Configure flow control
* @hw: pointer to the HW structure
*
- * Configures collision distance and flow control for fiber and serdes
- * links. Upon successful setup, poll for link.
+ * Write the flow control settings to the Transmit Config Word Register (TXCW)
+ * base on the flow control settings in e1000_mac_info.
**/
-s32 e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw)
+s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
- u32 ctrl;
- s32 ret_val = E1000_SUCCESS;
-
- DEBUGFUNC("e1000_setup_fiber_serdes_link_generic");
-
- ctrl = E1000_READ_REG(hw, E1000_CTRL);
-
- /* Take the link out of reset */
- ctrl &= ~E1000_CTRL_LRST;
-
- mac->ops.config_collision_dist(hw);
-
- ret_val = e1000_commit_fc_settings_generic(hw);
- if (ret_val)
- goto out;
-
- /*
- * Since auto-negotiation is enabled, take the link out of reset (the
- * link will be in reset, because we previously reset the chip). This
- * will restart auto-negotiation. If auto-negotiation is successful
- * then the link-up status bit will be set and the flow control enable
- * bits (RFCE and TFCE) will be set according to their negotiated value.
- */
- DEBUGOUT("Auto-negotiation enabled\n");
+ u32 txcw;
- E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
- E1000_WRITE_FLUSH(hw);
- msec_delay(1);
+ DEBUGFUNC("e1000_commit_fc_settings_generic");
/*
- * For these adapters, the SW definable pin 1 is set when the optics
- * detect a signal. If we have a signal, then poll for a "Link-Up"
- * indication.
+ * Check for a software override of the flow control settings, and
+ * setup the device accordingly. If auto-negotiation is enabled, then
+ * software will have to set the "PAUSE" bits to the correct value in
+ * the Transmit Config Word Register (TXCW) and re-start auto-
+ * negotiation. However, if auto-negotiation is disabled, then
+ * software will have to manually configure the two flow control enable
+ * bits in the CTRL register.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause frames,
+ * but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames but we
+ * do not support receiving pause frames).
+ * 3: Both Rx and Tx flow control (symmetric) are enabled.
*/
- if (hw->phy.media_type == e1000_media_type_internal_serdes ||
- (E1000_READ_REG(hw, E1000_CTRL) & E1000_CTRL_SWDPIN1)) {
- ret_val = e1000_poll_fiber_serdes_link_generic(hw);
- } else {
- DEBUGOUT("No signal detected\n");
+ switch (hw->fc.current_mode) {
+ case e1000_fc_none:
+ /* Flow control completely disabled by a software over-ride. */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
+ break;
+ case e1000_fc_rx_pause:
+ /*
+ * Rx Flow control is enabled and Tx Flow control is disabled
+ * by a software over-ride. Since there really isn't a way to
+ * advertise that we are capable of Rx Pause ONLY, we will
+ * advertise that we support both symmetric and asymmetric Rx
+ * PAUSE. Later, we will disable the adapter's ability to send
+ * PAUSE frames.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+ break;
+ case e1000_fc_tx_pause:
+ /*
+ * Tx Flow control is enabled, and Rx Flow control is disabled,
+ * by a software over-ride.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
+ break;
+ case e1000_fc_full:
+ /*
+ * Flow control (both Rx and Tx) is enabled by a software
+ * over-ride.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+ break;
+ default:
+ DEBUGOUT("Flow control param set incorrectly\n");
+ return -E1000_ERR_CONFIG;
+ break;
}
-out:
- return ret_val;
-}
-
-/**
- * e1000_config_collision_dist_generic - Configure collision distance
- * @hw: pointer to the HW structure
- *
- * Configures the collision distance to the default value and is used
- * during link setup.
- **/
-void e1000_config_collision_dist_generic(struct e1000_hw *hw)
-{
- u32 tctl;
-
- DEBUGFUNC("e1000_config_collision_dist_generic");
-
- tctl = E1000_READ_REG(hw, E1000_TCTL);
-
- tctl &= ~E1000_TCTL_COLD;
- tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+ E1000_WRITE_REG(hw, E1000_TXCW, txcw);
+ mac->txcw = txcw;
- E1000_WRITE_REG(hw, E1000_TCTL, tctl);
- E1000_WRITE_FLUSH(hw);
+ return E1000_SUCCESS;
}
/**
@@ -1101,7 +1129,7 @@ s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
u32 i, status;
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
DEBUGFUNC("e1000_poll_fiber_serdes_link_generic");
@@ -1120,7 +1148,7 @@ s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw)
}
if (i == FIBER_LINK_UP_LIMIT) {
DEBUGOUT("Never got a valid link from auto-neg!!!\n");
- mac->autoneg_failed = 1;
+ mac->autoneg_failed = TRUE;
/*
* AutoNeg failed to achieve a link, so we'll call
* mac->check_for_link. This routine will force the
@@ -1130,95 +1158,93 @@ s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw)
ret_val = mac->ops.check_for_link(hw);
if (ret_val) {
DEBUGOUT("Error while checking for link\n");
- goto out;
+ return ret_val;
}
- mac->autoneg_failed = 0;
+ mac->autoneg_failed = FALSE;
} else {
- mac->autoneg_failed = 0;
+ mac->autoneg_failed = FALSE;
DEBUGOUT("Valid Link Found\n");
}
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
- * e1000_commit_fc_settings_generic - Configure flow control
+ * e1000_setup_fiber_serdes_link_generic - Setup link for fiber/serdes
* @hw: pointer to the HW structure
*
- * Write the flow control settings to the Transmit Config Word Register (TXCW)
- * base on the flow control settings in e1000_mac_info.
+ * Configures collision distance and flow control for fiber and serdes
+ * links. Upon successful setup, poll for link.
**/
-s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw)
+s32 e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw)
{
- struct e1000_mac_info *mac = &hw->mac;
- u32 txcw;
- s32 ret_val = E1000_SUCCESS;
+ u32 ctrl;
+ s32 ret_val;
- DEBUGFUNC("e1000_commit_fc_settings_generic");
+ DEBUGFUNC("e1000_setup_fiber_serdes_link_generic");
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+ /* Take the link out of reset */
+ ctrl &= ~E1000_CTRL_LRST;
+
+ hw->mac.ops.config_collision_dist(hw);
+
+ ret_val = e1000_commit_fc_settings_generic(hw);
+ if (ret_val)
+ return ret_val;
/*
- * Check for a software override of the flow control settings, and
- * setup the device accordingly. If auto-negotiation is enabled, then
- * software will have to set the "PAUSE" bits to the correct value in
- * the Transmit Config Word Register (TXCW) and re-start auto-
- * negotiation. However, if auto-negotiation is disabled, then
- * software will have to manually configure the two flow control enable
- * bits in the CTRL register.
- *
- * The possible values of the "fc" parameter are:
- * 0: Flow control is completely disabled
- * 1: Rx flow control is enabled (we can receive pause frames,
- * but not send pause frames).
- * 2: Tx flow control is enabled (we can send pause frames but we
- * do not support receiving pause frames).
- * 3: Both Rx and Tx flow control (symmetric) are enabled.
+ * Since auto-negotiation is enabled, take the link out of reset (the
+ * link will be in reset, because we previously reset the chip). This
+ * will restart auto-negotiation. If auto-negotiation is successful
+ * then the link-up status bit will be set and the flow control enable
+ * bits (RFCE and TFCE) will be set according to their negotiated value.
*/
- switch (hw->fc.current_mode) {
- case e1000_fc_none:
- /* Flow control completely disabled by a software over-ride. */
- txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
- break;
- case e1000_fc_rx_pause:
- /*
- * Rx Flow control is enabled and Tx Flow control is disabled
- * by a software over-ride. Since there really isn't a way to
- * advertise that we are capable of Rx Pause ONLY, we will
- * advertise that we support both symmetric and asymmetric Rx
- * PAUSE. Later, we will disable the adapter's ability to send
- * PAUSE frames.
- */
- txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
- break;
- case e1000_fc_tx_pause:
- /*
- * Tx Flow control is enabled, and Rx Flow control is disabled,
- * by a software over-ride.
- */
- txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
- break;
- case e1000_fc_full:
- /*
- * Flow control (both Rx and Tx) is enabled by a software
- * over-ride.
- */
- txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
- break;
- default:
- DEBUGOUT("Flow control param set incorrectly\n");
- ret_val = -E1000_ERR_CONFIG;
- goto out;
- break;
- }
+ DEBUGOUT("Auto-negotiation enabled\n");
- E1000_WRITE_REG(hw, E1000_TXCW, txcw);
- mac->txcw = txcw;
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+ E1000_WRITE_FLUSH(hw);
+ msec_delay(1);
+
+ /*
+ * For these adapters, the SW definable pin 1 is set when the optics
+ * detect a signal. If we have a signal, then poll for a "Link-Up"
+ * indication.
+ */
+ if (hw->phy.media_type == e1000_media_type_internal_serdes ||
+ (E1000_READ_REG(hw, E1000_CTRL) & E1000_CTRL_SWDPIN1)) {
+ ret_val = e1000_poll_fiber_serdes_link_generic(hw);
+ } else {
+ DEBUGOUT("No signal detected\n");
+ }
-out:
return ret_val;
}
/**
+ * e1000_config_collision_dist_generic - Configure collision distance
+ * @hw: pointer to the HW structure
+ *
+ * Configures the collision distance to the default value and is used
+ * during link setup.
+ **/
+static void e1000_config_collision_dist_generic(struct e1000_hw *hw)
+{
+ u32 tctl;
+
+ DEBUGFUNC("e1000_config_collision_dist_generic");
+
+ tctl = E1000_READ_REG(hw, E1000_TCTL);
+
+ tctl &= ~E1000_TCTL_COLD;
+ tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+
+ E1000_WRITE_REG(hw, E1000_TCTL, tctl);
+ E1000_WRITE_FLUSH(hw);
+}
+
+/**
* e1000_set_fc_watermarks_generic - Set flow control high/low watermarks
* @hw: pointer to the HW structure
*
@@ -1258,48 +1284,6 @@ s32 e1000_set_fc_watermarks_generic(struct e1000_hw *hw)
}
/**
- * e1000_set_default_fc_generic - Set flow control default values
- * @hw: pointer to the HW structure
- *
- * Read the EEPROM for the default values for flow control and store the
- * values.
- **/
-s32 e1000_set_default_fc_generic(struct e1000_hw *hw)
-{
- s32 ret_val = E1000_SUCCESS;
- u16 nvm_data;
-
- DEBUGFUNC("e1000_set_default_fc_generic");
-
- /*
- * Read and store word 0x0F of the EEPROM. This word contains bits
- * that determine the hardware's default PAUSE (flow control) mode,
- * a bit that determines whether the HW defaults to enabling or
- * disabling auto-negotiation, and the direction of the
- * SW defined pins. If there is no SW over-ride of the flow
- * control setting, then the variable hw->fc will
- * be initialized based on a value in the EEPROM.
- */
- ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data);
-
- if (ret_val) {
- DEBUGOUT("NVM Read Error\n");
- goto out;
- }
-
- if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0)
- hw->fc.requested_mode = e1000_fc_none;
- else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) ==
- NVM_WORD0F_ASM_DIR)
- hw->fc.requested_mode = e1000_fc_tx_pause;
- else
- hw->fc.requested_mode = e1000_fc_full;
-
-out:
- return ret_val;
-}
-
-/**
* e1000_force_mac_fc_generic - Force the MAC's flow control settings
* @hw: pointer to the HW structure
*
@@ -1312,7 +1296,6 @@ out:
s32 e1000_force_mac_fc_generic(struct e1000_hw *hw)
{
u32 ctrl;
- s32 ret_val = E1000_SUCCESS;
DEBUGFUNC("e1000_force_mac_fc_generic");
@@ -1355,14 +1338,12 @@ s32 e1000_force_mac_fc_generic(struct e1000_hw *hw)
break;
default:
DEBUGOUT("Flow control param set incorrectly\n");
- ret_val = -E1000_ERR_CONFIG;
- goto out;
+ return -E1000_ERR_CONFIG;
}
E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -1400,7 +1381,7 @@ s32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw)
if (ret_val) {
DEBUGOUT("Error forcing flow control settings\n");
- goto out;
+ return ret_val;
}
/*
@@ -1417,14 +1398,14 @@ s32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw)
*/
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
if (ret_val)
- goto out;
+ return ret_val;
if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
DEBUGOUT("Copper PHY and Auto Neg has not completed.\n");
- goto out;
+ return ret_val;
}
/*
@@ -1437,11 +1418,11 @@ s32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw)
ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
&mii_nway_adv_reg);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY,
&mii_nway_lp_ability_reg);
if (ret_val)
- goto out;
+ return ret_val;
/*
* Two bits in the Auto Negotiation Advertisement Register
@@ -1540,7 +1521,7 @@ s32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw)
ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex);
if (ret_val) {
DEBUGOUT("Error getting link speed and duplex\n");
- goto out;
+ return ret_val;
}
if (duplex == HALF_DUPLEX)
@@ -1553,12 +1534,11 @@ s32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw)
ret_val = e1000_force_mac_fc_generic(hw);
if (ret_val) {
DEBUGOUT("Error forcing flow control settings\n");
- goto out;
+ return ret_val;
}
}
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -1629,7 +1609,6 @@ s32 e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw,
s32 e1000_get_hw_semaphore_generic(struct e1000_hw *hw)
{
u32 swsm;
- s32 ret_val = E1000_SUCCESS;
s32 timeout = hw->nvm.word_size + 1;
s32 i = 0;
@@ -1647,8 +1626,7 @@ s32 e1000_get_hw_semaphore_generic(struct e1000_hw *hw)
if (i == timeout) {
DEBUGOUT("Driver can't access device - SMBI bit is set.\n");
- ret_val = -E1000_ERR_NVM;
- goto out;
+ return -E1000_ERR_NVM;
}
/* Get the FW semaphore. */
@@ -1667,12 +1645,10 @@ s32 e1000_get_hw_semaphore_generic(struct e1000_hw *hw)
/* Release semaphores */
e1000_put_hw_semaphore_generic(hw);
DEBUGOUT("Driver can't access the NVM\n");
- ret_val = -E1000_ERR_NVM;
- goto out;
+ return -E1000_ERR_NVM;
}
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -1703,7 +1679,6 @@ void e1000_put_hw_semaphore_generic(struct e1000_hw *hw)
s32 e1000_get_auto_rd_done_generic(struct e1000_hw *hw)
{
s32 i = 0;
- s32 ret_val = E1000_SUCCESS;
DEBUGFUNC("e1000_get_auto_rd_done_generic");
@@ -1716,12 +1691,10 @@ s32 e1000_get_auto_rd_done_generic(struct e1000_hw *hw)
if (i == AUTO_READ_DONE_TIMEOUT) {
DEBUGOUT("Auto read by HW from NVM has not completed.\n");
- ret_val = -E1000_ERR_RESET;
- goto out;
+ return -E1000_ERR_RESET;
}
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -1741,14 +1714,13 @@ s32 e1000_valid_led_default_generic(struct e1000_hw *hw, u16 *data)
ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
if (ret_val) {
DEBUGOUT("NVM Read Error\n");
- goto out;
+ return ret_val;
}
if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
*data = ID_LED_DEFAULT;
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -1770,7 +1742,7 @@ s32 e1000_id_led_init_generic(struct e1000_hw *hw)
ret_val = hw->nvm.ops.valid_led_default(hw, &data);
if (ret_val)
- goto out;
+ return ret_val;
mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL);
mac->ledctl_mode1 = mac->ledctl_default;
@@ -1814,8 +1786,7 @@ s32 e1000_id_led_init_generic(struct e1000_hw *hw)
}
}
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -1828,14 +1799,11 @@ out:
s32 e1000_setup_led_generic(struct e1000_hw *hw)
{
u32 ledctl;
- s32 ret_val = E1000_SUCCESS;
DEBUGFUNC("e1000_setup_led_generic");
- if (hw->mac.ops.setup_led != e1000_setup_led_generic) {
- ret_val = -E1000_ERR_CONFIG;
- goto out;
- }
+ if (hw->mac.ops.setup_led != e1000_setup_led_generic)
+ return -E1000_ERR_CONFIG;
if (hw->phy.media_type == e1000_media_type_fiber) {
ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
@@ -1850,8 +1818,7 @@ s32 e1000_setup_led_generic(struct e1000_hw *hw)
E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
}
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -1976,7 +1943,7 @@ void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop)
DEBUGFUNC("e1000_set_pcie_no_snoop_generic");
if (hw->bus.type != e1000_bus_type_pci_express)
- goto out;
+ return;
if (no_snoop) {
gcr = E1000_READ_REG(hw, E1000_GCR);
@@ -1984,8 +1951,6 @@ void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop)
gcr |= no_snoop;
E1000_WRITE_REG(hw, E1000_GCR, gcr);
}
-out:
- return;
}
/**
@@ -2003,12 +1968,11 @@ s32 e1000_disable_pcie_master_generic(struct e1000_hw *hw)
{
u32 ctrl;
s32 timeout = MASTER_DISABLE_TIMEOUT;
- s32 ret_val = E1000_SUCCESS;
DEBUGFUNC("e1000_disable_pcie_master_generic");
if (hw->bus.type != e1000_bus_type_pci_express)
- goto out;
+ return E1000_SUCCESS;
ctrl = E1000_READ_REG(hw, E1000_CTRL);
ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
@@ -2024,11 +1988,10 @@ s32 e1000_disable_pcie_master_generic(struct e1000_hw *hw)
if (!timeout) {
DEBUGOUT("Master requests are pending.\n");
- ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING;
+ return -E1000_ERR_MASTER_REQUESTS_PENDING;
}
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -2045,7 +2008,7 @@ void e1000_reset_adaptive_generic(struct e1000_hw *hw)
if (!mac->adaptive_ifs) {
DEBUGOUT("Not in Adaptive IFS mode!\n");
- goto out;
+ return;
}
mac->current_ifs_val = 0;
@@ -2056,8 +2019,6 @@ void e1000_reset_adaptive_generic(struct e1000_hw *hw)
mac->in_ifs_mode = FALSE;
E1000_WRITE_REG(hw, E1000_AIT, 0);
-out:
- return;
}
/**
@@ -2075,7 +2036,7 @@ void e1000_update_adaptive_generic(struct e1000_hw *hw)
if (!mac->adaptive_ifs) {
DEBUGOUT("Not in Adaptive IFS mode!\n");
- goto out;
+ return;
}
if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) {
@@ -2099,8 +2060,6 @@ void e1000_update_adaptive_generic(struct e1000_hw *hw)
E1000_WRITE_REG(hw, E1000_AIT, 0);
}
}
-out:
- return;
}
/**
@@ -2112,19 +2071,15 @@ out:
**/
static s32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw)
{
- s32 ret_val = E1000_SUCCESS;
-
DEBUGFUNC("e1000_validate_mdi_setting_generic");
if (!hw->mac.autoneg && (hw->phy.mdix == 0 || hw->phy.mdix == 3)) {
DEBUGOUT("Invalid MDI setting detected\n");
hw->phy.mdix = 1;
- ret_val = -E1000_ERR_CONFIG;
- goto out;
+ return -E1000_ERR_CONFIG;
}
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -2142,7 +2097,6 @@ s32 e1000_write_8bit_ctrl_reg_generic(struct e1000_hw *hw, u32 reg,
u32 offset, u8 data)
{
u32 i, regvalue = 0;
- s32 ret_val = E1000_SUCCESS;
DEBUGFUNC("e1000_write_8bit_ctrl_reg_generic");
@@ -2159,10 +2113,8 @@ s32 e1000_write_8bit_ctrl_reg_generic(struct e1000_hw *hw, u32 reg,
}
if (!(regvalue & E1000_GEN_CTL_READY)) {
DEBUGOUT1("Reg %08x did not indicate ready\n", reg);
- ret_val = -E1000_ERR_PHY;
- goto out;
+ return -E1000_ERR_PHY;
}
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
diff --git a/sys/dev/e1000/e1000_mac.h b/sys/dev/e1000/e1000_mac.h
index 11ffab7..c18a7ec 100644
--- a/sys/dev/e1000/e1000_mac.h
+++ b/sys/dev/e1000/e1000_mac.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2010, Intel Corporation
+ Copyright (c) 2001-2012, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -64,31 +64,29 @@ void e1000_set_lan_id_single_port(struct e1000_hw *hw);
void e1000_set_lan_id_multi_port_pci(struct e1000_hw *hw);
s32 e1000_get_hw_semaphore_generic(struct e1000_hw *hw);
s32 e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed,
- u16 *duplex);
+ u16 *duplex);
s32 e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw,
- u16 *speed, u16 *duplex);
+ u16 *speed, u16 *duplex);
s32 e1000_id_led_init_generic(struct e1000_hw *hw);
s32 e1000_led_on_generic(struct e1000_hw *hw);
s32 e1000_led_off_generic(struct e1000_hw *hw);
void e1000_update_mc_addr_list_generic(struct e1000_hw *hw,
- u8 *mc_addr_list, u32 mc_addr_count);
+ u8 *mc_addr_list, u32 mc_addr_count);
s32 e1000_set_default_fc_generic(struct e1000_hw *hw);
s32 e1000_set_fc_watermarks_generic(struct e1000_hw *hw);
s32 e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw);
s32 e1000_setup_led_generic(struct e1000_hw *hw);
s32 e1000_setup_link_generic(struct e1000_hw *hw);
s32 e1000_write_8bit_ctrl_reg_generic(struct e1000_hw *hw, u32 reg,
- u32 offset, u8 data);
+ u32 offset, u8 data);
u32 e1000_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr);
void e1000_clear_hw_cntrs_base_generic(struct e1000_hw *hw);
void e1000_clear_vfta_generic(struct e1000_hw *hw);
-void e1000_config_collision_dist_generic(struct e1000_hw *hw);
void e1000_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count);
void e1000_pcix_mmrbc_workaround_generic(struct e1000_hw *hw);
void e1000_put_hw_semaphore_generic(struct e1000_hw *hw);
-void e1000_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index);
s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw);
void e1000_reset_adaptive_generic(struct e1000_hw *hw);
void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop);
diff --git a/sys/dev/e1000/e1000_manage.c b/sys/dev/e1000/e1000_manage.c
index 7782739..f11b18d 100644
--- a/sys/dev/e1000/e1000_manage.c
+++ b/sys/dev/e1000/e1000_manage.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2010, Intel Corporation
+ Copyright (c) 2001-2012, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -71,23 +71,20 @@ u8 e1000_calculate_checksum(u8 *buffer, u32 length)
s32 e1000_mng_enable_host_if_generic(struct e1000_hw *hw)
{
u32 hicr;
- s32 ret_val = E1000_SUCCESS;
u8 i;
DEBUGFUNC("e1000_mng_enable_host_if_generic");
- if (!(hw->mac.arc_subsystem_valid)) {
+ if (!hw->mac.arc_subsystem_valid) {
DEBUGOUT("ARC subsystem not valid.\n");
- ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
- goto out;
+ return -E1000_ERR_HOST_INTERFACE_COMMAND;
}
/* Check that the host interface is enabled. */
hicr = E1000_READ_REG(hw, E1000_HICR);
- if ((hicr & E1000_HICR_EN) == 0) {
+ if (!(hicr & E1000_HICR_EN)) {
DEBUGOUT("E1000_HOST_EN bit disabled.\n");
- ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
- goto out;
+ return -E1000_ERR_HOST_INTERFACE_COMMAND;
}
/* check the previous command is completed */
for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
@@ -99,12 +96,10 @@ s32 e1000_mng_enable_host_if_generic(struct e1000_hw *hw)
if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
DEBUGOUT("Previous command timeout failed .\n");
- ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
- goto out;
+ return -E1000_ERR_HOST_INTERFACE_COMMAND;
}
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -122,7 +117,7 @@ bool e1000_check_mng_mode_generic(struct e1000_hw *hw)
return (fwsm & E1000_FWSM_MODE_MASK) ==
- (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
+ (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
}
/**
@@ -147,7 +142,7 @@ bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw)
/* No manageability, no filtering */
if (!hw->mac.ops.check_mng_mode(hw)) {
hw->mac.tx_pkt_filtering = FALSE;
- goto out;
+ return hw->mac.tx_pkt_filtering;
}
/*
@@ -157,7 +152,7 @@ bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw)
ret_val = hw->mac.ops.mng_enable_host_if(hw);
if (ret_val != E1000_SUCCESS) {
hw->mac.tx_pkt_filtering = FALSE;
- goto out;
+ return hw->mac.tx_pkt_filtering;
}
/* Read in the header. Length and offset are in dwords. */
@@ -165,11 +160,11 @@ bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw)
offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2;
for (i = 0; i < len; i++)
*(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF,
- offset + i);
+ offset + i);
hdr_csum = hdr->checksum;
hdr->checksum = 0;
csum = e1000_calculate_checksum((u8 *)hdr,
- E1000_MNG_DHCP_COOKIE_LENGTH);
+ E1000_MNG_DHCP_COOKIE_LENGTH);
/*
* If either the checksums or signature don't match, then
* the cookie area isn't considered valid, in which case we
@@ -177,67 +172,17 @@ bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw)
*/
if ((hdr_csum != csum) || (hdr->signature != E1000_IAMT_SIGNATURE)) {
hw->mac.tx_pkt_filtering = TRUE;
- goto out;
+ return hw->mac.tx_pkt_filtering;
}
/* Cookie area is valid, make the final check for filtering. */
- if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING)) {
+ if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING))
hw->mac.tx_pkt_filtering = FALSE;
- goto out;
- }
-out:
return hw->mac.tx_pkt_filtering;
}
/**
- * e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface
- * @hw: pointer to the HW structure
- * @buffer: pointer to the host interface
- * @length: size of the buffer
- *
- * Writes the DHCP information to the host interface.
- **/
-s32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, u8 *buffer,
- u16 length)
-{
- struct e1000_host_mng_command_header hdr;
- s32 ret_val;
- u32 hicr;
-
- DEBUGFUNC("e1000_mng_write_dhcp_info_generic");
-
- hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
- hdr.command_length = length;
- hdr.reserved1 = 0;
- hdr.reserved2 = 0;
- hdr.checksum = 0;
-
- /* Enable the host interface */
- ret_val = hw->mac.ops.mng_enable_host_if(hw);
- if (ret_val)
- goto out;
-
- /* Populate the host interface with the contents of "buffer". */
- ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length,
- sizeof(hdr), &(hdr.checksum));
- if (ret_val)
- goto out;
-
- /* Write the manageability command header */
- ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr);
- if (ret_val)
- goto out;
-
- /* Tell the ARC a new command is pending. */
- hicr = E1000_READ_REG(hw, E1000_HICR);
- E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
-
-out:
- return ret_val;
-}
-
-/**
* e1000_mng_write_cmd_header_generic - Writes manageability command header
* @hw: pointer to the HW structure
* @hdr: pointer to the host interface command header
@@ -245,7 +190,7 @@ out:
* Writes the command header after does the checksum calculation.
**/
s32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
- struct e1000_host_mng_command_header *hdr)
+ struct e1000_host_mng_command_header *hdr)
{
u16 i, length = sizeof(struct e1000_host_mng_command_header);
@@ -259,7 +204,7 @@ s32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
/* Write the relevant command block into the ram area. */
for (i = 0; i < length; i++) {
E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i,
- *((u32 *) hdr + i));
+ *((u32 *) hdr + i));
E1000_WRITE_FLUSH(hw);
}
@@ -279,22 +224,19 @@ s32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
* way. Also fills up the sum of the buffer in *buffer parameter.
**/
s32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
- u16 length, u16 offset, u8 *sum)
+ u16 length, u16 offset, u8 *sum)
{
u8 *tmp;
u8 *bufptr = buffer;
u32 data = 0;
- s32 ret_val = E1000_SUCCESS;
u16 remaining, i, j, prev_bytes;
DEBUGFUNC("e1000_mng_host_if_write_generic");
/* sum = only sum of the data and it is not checksum */
- if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) {
- ret_val = -E1000_ERR_PARAM;
- goto out;
- }
+ if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH)
+ return -E1000_ERR_PARAM;
tmp = (u8 *)&data;
prev_bytes = offset & 0x3;
@@ -328,7 +270,7 @@ s32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
}
E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i,
- data);
+ data);
}
if (remaining) {
for (j = 0; j < sizeof(u32); j++) {
@@ -339,11 +281,57 @@ s32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
*sum += *(tmp + j);
}
- E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, data);
+ E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i,
+ data);
}
-out:
- return ret_val;
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface
+ * @hw: pointer to the HW structure
+ * @buffer: pointer to the host interface
+ * @length: size of the buffer
+ *
+ * Writes the DHCP information to the host interface.
+ **/
+s32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, u8 *buffer,
+ u16 length)
+{
+ struct e1000_host_mng_command_header hdr;
+ s32 ret_val;
+ u32 hicr;
+
+ DEBUGFUNC("e1000_mng_write_dhcp_info_generic");
+
+ hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
+ hdr.command_length = length;
+ hdr.reserved1 = 0;
+ hdr.reserved2 = 0;
+ hdr.checksum = 0;
+
+ /* Enable the host interface */
+ ret_val = hw->mac.ops.mng_enable_host_if(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Populate the host interface with the contents of "buffer". */
+ ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length,
+ sizeof(hdr), &(hdr.checksum));
+ if (ret_val)
+ return ret_val;
+
+ /* Write the manageability command header */
+ ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr);
+ if (ret_val)
+ return ret_val;
+
+ /* Tell the ARC a new command is pending. */
+ hicr = E1000_READ_REG(hw, E1000_HICR);
+ E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
+
+ return E1000_SUCCESS;
}
/**
@@ -357,17 +345,16 @@ bool e1000_enable_mng_pass_thru(struct e1000_hw *hw)
{
u32 manc;
u32 fwsm, factps;
- bool ret_val = FALSE;
DEBUGFUNC("e1000_enable_mng_pass_thru");
if (!hw->mac.asf_firmware_present)
- goto out;
+ return FALSE;
manc = E1000_READ_REG(hw, E1000_MANC);
if (!(manc & E1000_MANC_RCV_TCO_EN))
- goto out;
+ return FALSE;
if (hw->mac.has_fwsm) {
fwsm = E1000_READ_REG(hw, E1000_FWSM);
@@ -375,10 +362,8 @@ bool e1000_enable_mng_pass_thru(struct e1000_hw *hw)
if (!(factps & E1000_FACTPS_MNGCG) &&
((fwsm & E1000_FWSM_MODE_MASK) ==
- (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) {
- ret_val = TRUE;
- goto out;
- }
+ (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT)))
+ return TRUE;
} else if ((hw->mac.type == e1000_82574) ||
(hw->mac.type == e1000_82583)) {
u16 data;
@@ -388,18 +373,14 @@ bool e1000_enable_mng_pass_thru(struct e1000_hw *hw)
if (!(factps & E1000_FACTPS_MNGCG) &&
((data & E1000_NVM_INIT_CTRL2_MNGM) ==
- (e1000_mng_mode_pt << 13))) {
- ret_val = TRUE;
- goto out;
- }
+ (e1000_mng_mode_pt << 13)))
+ return TRUE;
} else if ((manc & E1000_MANC_SMBUS_EN) &&
- !(manc & E1000_MANC_ASF_EN)) {
- ret_val = TRUE;
- goto out;
+ !(manc & E1000_MANC_ASF_EN)) {
+ return TRUE;
}
-out:
- return ret_val;
+ return FALSE;
}
/**
@@ -414,33 +395,30 @@ out:
s32 e1000_host_interface_command(struct e1000_hw *hw, u8 *buffer, u32 length)
{
u32 hicr, i;
- s32 ret_val = E1000_SUCCESS;
DEBUGFUNC("e1000_host_interface_command");
if (!(hw->mac.arc_subsystem_valid)) {
DEBUGOUT("Hardware doesn't support host interface command.\n");
- goto out;
+ return E1000_SUCCESS;
}
if (!hw->mac.asf_firmware_present) {
DEBUGOUT("Firmware is not present.\n");
- goto out;
+ return E1000_SUCCESS;
}
if (length == 0 || length & 0x3 ||
length > E1000_HI_MAX_BLOCK_BYTE_LENGTH) {
DEBUGOUT("Buffer length failure.\n");
- ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
- goto out;
+ return -E1000_ERR_HOST_INTERFACE_COMMAND;
}
/* Check that the host interface is enabled. */
hicr = E1000_READ_REG(hw, E1000_HICR);
- if ((hicr & E1000_HICR_EN) == 0) {
+ if (!(hicr & E1000_HICR_EN)) {
DEBUGOUT("E1000_HOST_EN bit disabled.\n");
- ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
- goto out;
+ return -E1000_ERR_HOST_INTERFACE_COMMAND;
}
/* Calculate length in DWORDs */
@@ -451,10 +429,8 @@ s32 e1000_host_interface_command(struct e1000_hw *hw, u8 *buffer, u32 length)
* into the ram area.
*/
for (i = 0; i < length; i++)
- E1000_WRITE_REG_ARRAY_DWORD(hw,
- E1000_HOST_IF,
- i,
- *((u32 *)buffer + i));
+ E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i,
+ *((u32 *)buffer + i));
/* Setting this bit tells the ARC that a new command is pending. */
E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
@@ -470,16 +446,134 @@ s32 e1000_host_interface_command(struct e1000_hw *hw, u8 *buffer, u32 length)
if (i == E1000_HI_COMMAND_TIMEOUT ||
(!(E1000_READ_REG(hw, E1000_HICR) & E1000_HICR_SV))) {
DEBUGOUT("Command has failed with no status valid.\n");
- ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
- goto out;
+ return -E1000_ERR_HOST_INTERFACE_COMMAND;
}
for (i = 0; i < length; i++)
*((u32 *)buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw,
- E1000_HOST_IF,
- i);
+ E1000_HOST_IF,
+ i);
+
+ return E1000_SUCCESS;
+}
+/**
+ * e1000_load_firmware - Writes proxy FW code buffer to host interface
+ * and execute.
+ * @hw: pointer to the HW structure
+ * @buffer: contains a firmware to write
+ * @length: the byte length of the buffer, must be multiple of 4 bytes
+ *
+ * Upon success returns E1000_SUCCESS, returns E1000_ERR_CONFIG if not enabled
+ * in HW else returns E1000_ERR_HOST_INTERFACE_COMMAND.
+ **/
+s32 e1000_load_firmware(struct e1000_hw *hw, u8 *buffer, u32 length)
+{
+ u32 hicr, hibba, fwsm, icr, i;
+
+ DEBUGFUNC("e1000_load_firmware");
+
+ if (hw->mac.type < e1000_i210) {
+ DEBUGOUT("Hardware doesn't support loading FW by the driver\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ /* Check that the host interface is enabled. */
+ hicr = E1000_READ_REG(hw, E1000_HICR);
+ if (!(hicr & E1000_HICR_EN)) {
+ DEBUGOUT("E1000_HOST_EN bit disabled.\n");
+ return -E1000_ERR_CONFIG;
+ }
+ if (!(hicr & E1000_HICR_MEMORY_BASE_EN)) {
+ DEBUGOUT("E1000_HICR_MEMORY_BASE_EN bit disabled.\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ if (length == 0 || length & 0x3 || length > E1000_HI_FW_MAX_LENGTH) {
+ DEBUGOUT("Buffer length failure.\n");
+ return -E1000_ERR_INVALID_ARGUMENT;
+ }
+
+ /* Clear notification from ROM-FW by reading ICR register */
+ icr = E1000_READ_REG(hw, E1000_ICR_V2);
+
+ /* Reset ROM-FW */
+ hicr = E1000_READ_REG(hw, E1000_HICR);
+ hicr |= E1000_HICR_FW_RESET_ENABLE;
+ E1000_WRITE_REG(hw, E1000_HICR, hicr);
+ hicr |= E1000_HICR_FW_RESET;
+ E1000_WRITE_REG(hw, E1000_HICR, hicr);
+ E1000_WRITE_FLUSH(hw);
+
+ /* Wait till MAC notifies about its readiness after ROM-FW reset */
+ for (i = 0; i < (E1000_HI_COMMAND_TIMEOUT * 2); i++) {
+ icr = E1000_READ_REG(hw, E1000_ICR_V2);
+ if (icr & E1000_ICR_MNG)
+ break;
+ msec_delay(1);
+ }
+
+ /* Check for timeout */
+ if (i == E1000_HI_COMMAND_TIMEOUT) {
+ DEBUGOUT("FW reset failed.\n");
+ return -E1000_ERR_HOST_INTERFACE_COMMAND;
+ }
+
+ /* Wait till MAC is ready to accept new FW code */
+ for (i = 0; i < E1000_HI_COMMAND_TIMEOUT; i++) {
+ fwsm = E1000_READ_REG(hw, E1000_FWSM);
+ if ((fwsm & E1000_FWSM_FW_VALID) &&
+ ((fwsm & E1000_FWSM_MODE_MASK) >> E1000_FWSM_MODE_SHIFT ==
+ E1000_FWSM_HI_EN_ONLY_MODE))
+ break;
+ msec_delay(1);
+ }
+
+ /* Check for timeout */
+ if (i == E1000_HI_COMMAND_TIMEOUT) {
+ DEBUGOUT("FW reset failed.\n");
+ return -E1000_ERR_HOST_INTERFACE_COMMAND;
+ }
+
+ /* Calculate length in DWORDs */
+ length >>= 2;
+
+ /*
+ * The device driver writes the relevant FW code block
+ * into the ram area in DWORDs via 1kB ram addressing window.
+ */
+ for (i = 0; i < length; i++) {
+ if (!(i % E1000_HI_FW_BLOCK_DWORD_LENGTH)) {
+ /* Point to correct 1kB ram window */
+ hibba = E1000_HI_FW_BASE_ADDRESS +
+ ((E1000_HI_FW_BLOCK_DWORD_LENGTH << 2) *
+ (i / E1000_HI_FW_BLOCK_DWORD_LENGTH));
+
+ E1000_WRITE_REG(hw, E1000_HIBBA, hibba);
+ }
+
+ E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF,
+ i % E1000_HI_FW_BLOCK_DWORD_LENGTH,
+ *((u32 *)buffer + i));
+ }
-out:
- return ret_val;
+ /* Setting this bit tells the ARC that a new FW is ready to execute. */
+ hicr = E1000_READ_REG(hw, E1000_HICR);
+ E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
+
+ for (i = 0; i < E1000_HI_COMMAND_TIMEOUT; i++) {
+ hicr = E1000_READ_REG(hw, E1000_HICR);
+ if (!(hicr & E1000_HICR_C))
+ break;
+ msec_delay(1);
+ }
+
+ /* Check for successful FW start. */
+ if (i == E1000_HI_COMMAND_TIMEOUT) {
+ DEBUGOUT("New FW did not start within timeout period.\n");
+ return -E1000_ERR_HOST_INTERFACE_COMMAND;
+ }
+
+ return E1000_SUCCESS;
}
+
diff --git a/sys/dev/e1000/e1000_manage.h b/sys/dev/e1000/e1000_manage.h
index 6a0c2a0..51f17671 100644
--- a/sys/dev/e1000/e1000_manage.h
+++ b/sys/dev/e1000/e1000_manage.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2010, Intel Corporation
+ Copyright (c) 2001-2012, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -39,14 +39,15 @@ bool e1000_check_mng_mode_generic(struct e1000_hw *hw);
bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw);
s32 e1000_mng_enable_host_if_generic(struct e1000_hw *hw);
s32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
- u16 length, u16 offset, u8 *sum);
+ u16 length, u16 offset, u8 *sum);
s32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
- struct e1000_host_mng_command_header *hdr);
+ struct e1000_host_mng_command_header *hdr);
s32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw,
- u8 *buffer, u16 length);
+ u8 *buffer, u16 length);
bool e1000_enable_mng_pass_thru(struct e1000_hw *hw);
u8 e1000_calculate_checksum(u8 *buffer, u32 length);
s32 e1000_host_interface_command(struct e1000_hw *hw, u8 *buffer, u32 length);
+s32 e1000_load_firmware(struct e1000_hw *hw, u8 *buffer, u32 length);
enum e1000_mng_mode {
e1000_mng_mode_none = 0,
@@ -56,35 +57,40 @@ enum e1000_mng_mode {
e1000_mng_mode_host_if_only
};
-#define E1000_FACTPS_MNGCG 0x20000000
+#define E1000_FACTPS_MNGCG 0x20000000
-#define E1000_FWSM_MODE_MASK 0xE
-#define E1000_FWSM_MODE_SHIFT 1
+#define E1000_FWSM_MODE_MASK 0xE
+#define E1000_FWSM_MODE_SHIFT 1
+#define E1000_FWSM_FW_VALID 0x00008000
+#define E1000_FWSM_HI_EN_ONLY_MODE 0x4
-#define E1000_MNG_IAMT_MODE 0x3
-#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10
-#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0
-#define E1000_MNG_DHCP_COMMAND_TIMEOUT 10
-#define E1000_MNG_DHCP_TX_PAYLOAD_CMD 64
-#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING 0x1
-#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN 0x2
+#define E1000_MNG_IAMT_MODE 0x3
+#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10
+#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0
+#define E1000_MNG_DHCP_COMMAND_TIMEOUT 10
+#define E1000_MNG_DHCP_TX_PAYLOAD_CMD 64
+#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING 0x1
+#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN 0x2
-#define E1000_VFTA_ENTRY_SHIFT 5
-#define E1000_VFTA_ENTRY_MASK 0x7F
-#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK 0x1F
+#define E1000_VFTA_ENTRY_SHIFT 5
+#define E1000_VFTA_ENTRY_MASK 0x7F
+#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK 0x1F
-#define E1000_HI_MAX_BLOCK_BYTE_LENGTH 1792 /* Num of bytes in range */
-#define E1000_HI_MAX_BLOCK_DWORD_LENGTH 448 /* Num of dwords in range */
-#define E1000_HI_COMMAND_TIMEOUT 500 /* Process HI command limit */
-
-#define E1000_HICR_EN 0x01 /* Enable bit - RO */
+#define E1000_HI_MAX_BLOCK_BYTE_LENGTH 1792 /* Num of bytes in range */
+#define E1000_HI_MAX_BLOCK_DWORD_LENGTH 448 /* Num of dwords in range */
+#define E1000_HI_COMMAND_TIMEOUT 500 /* Process HI cmd limit */
+#define E1000_HI_FW_BASE_ADDRESS 0x10000
+#define E1000_HI_FW_MAX_LENGTH (64 * 1024) /* Num of bytes */
+#define E1000_HI_FW_BLOCK_DWORD_LENGTH 256 /* Num of DWORDs per page */
+#define E1000_HICR_MEMORY_BASE_EN 0x200 /* MB Enable bit - RO */
+#define E1000_HICR_EN 0x01 /* Enable bit - RO */
/* Driver sets this bit when done to put command in RAM */
-#define E1000_HICR_C 0x02
-#define E1000_HICR_SV 0x04 /* Status Validity */
-#define E1000_HICR_FW_RESET_ENABLE 0x40
-#define E1000_HICR_FW_RESET 0x80
+#define E1000_HICR_C 0x02
+#define E1000_HICR_SV 0x04 /* Status Validity */
+#define E1000_HICR_FW_RESET_ENABLE 0x40
+#define E1000_HICR_FW_RESET 0x80
/* Intel(R) Active Management Technology signature */
-#define E1000_IAMT_SIGNATURE 0x544D4149
+#define E1000_IAMT_SIGNATURE 0x544D4149
#endif
diff --git a/sys/dev/e1000/e1000_phy.c b/sys/dev/e1000/e1000_phy.c
index ead72690..fd253ba 100644
--- a/sys/dev/e1000/e1000_phy.c
+++ b/sys/dev/e1000/e1000_phy.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2011, Intel Corporation
+ Copyright (c) 2001-2012, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -95,8 +95,8 @@ void e1000_init_phy_ops_generic(struct e1000_hw *hw)
phy->ops.write_reg_page = e1000_null_write_reg;
phy->ops.power_up = e1000_null_phy_generic;
phy->ops.power_down = e1000_null_phy_generic;
- phy->ops.read_i2c_byte = e1000_read_i2c_byte_generic;
- phy->ops.write_i2c_byte = e1000_write_i2c_byte_generic;
+ phy->ops.read_i2c_byte = e1000_read_i2c_byte_null;
+ phy->ops.write_i2c_byte = e1000_write_i2c_byte_null;
phy->ops.cfg_on_link_up = e1000_null_ops_generic;
}
@@ -151,6 +151,36 @@ s32 e1000_null_write_reg(struct e1000_hw *hw, u32 offset, u16 data)
}
/**
+ * e1000_read_i2c_byte_null - No-op function, return 0
+ * @hw: pointer to hardware structure
+ * @byte_offset: byte offset to write
+ * @dev_addr: device address
+ * @data: data value read
+ *
+ **/
+s32 e1000_read_i2c_byte_null(struct e1000_hw *hw, u8 byte_offset,
+ u8 dev_addr, u8 *data)
+{
+ DEBUGFUNC("e1000_read_i2c_byte_null");
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_write_i2c_byte_null - No-op function, return 0
+ * @hw: pointer to hardware structure
+ * @byte_offset: byte offset to write
+ * @dev_addr: device address
+ * @data: data value to write
+ *
+ **/
+s32 e1000_write_i2c_byte_null(struct e1000_hw *hw, u8 byte_offset,
+ u8 dev_addr, u8 data)
+{
+ DEBUGFUNC("e1000_write_i2c_byte_null");
+ return E1000_SUCCESS;
+}
+
+/**
* e1000_check_reset_block_generic - Check if PHY reset is blocked
* @hw: pointer to the HW structure
*
@@ -186,30 +216,30 @@ s32 e1000_get_phy_id(struct e1000_hw *hw)
DEBUGFUNC("e1000_get_phy_id");
- if (!(phy->ops.read_reg))
- goto out;
+ if (!phy->ops.read_reg)
+ return E1000_SUCCESS;
while (retry_count < 2) {
ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
if (ret_val)
- goto out;
+ return ret_val;
phy->id = (u32)(phy_id << 16);
usec_delay(20);
ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
if (ret_val)
- goto out;
+ return ret_val;
phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
if (phy->id != 0 && phy->id != PHY_REVISION_MASK)
- goto out;
+ return E1000_SUCCESS;
retry_count++;
}
-out:
- return ret_val;
+
+ return E1000_SUCCESS;
}
/**
@@ -220,21 +250,18 @@ out:
**/
s32 e1000_phy_reset_dsp_generic(struct e1000_hw *hw)
{
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
DEBUGFUNC("e1000_phy_reset_dsp_generic");
- if (!(hw->phy.ops.write_reg))
- goto out;
+ if (!hw->phy.ops.write_reg)
+ return E1000_SUCCESS;
ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
if (ret_val)
- goto out;
-
- ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0);
+ return ret_val;
-out:
- return ret_val;
+ return hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0);
}
/**
@@ -250,7 +277,6 @@ s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
{
struct e1000_phy_info *phy = &hw->phy;
u32 i, mdic = 0;
- s32 ret_val = E1000_SUCCESS;
DEBUGFUNC("e1000_read_phy_reg_mdic");
@@ -283,13 +309,11 @@ s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
}
if (!(mdic & E1000_MDIC_READY)) {
DEBUGOUT("MDI Read did not complete\n");
- ret_val = -E1000_ERR_PHY;
- goto out;
+ return -E1000_ERR_PHY;
}
if (mdic & E1000_MDIC_ERROR) {
DEBUGOUT("MDI Error\n");
- ret_val = -E1000_ERR_PHY;
- goto out;
+ return -E1000_ERR_PHY;
}
*data = (u16) mdic;
@@ -300,8 +324,7 @@ s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
if (hw->mac.type == e1000_pch2lan)
usec_delay(100);
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -316,7 +339,6 @@ s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
{
struct e1000_phy_info *phy = &hw->phy;
u32 i, mdic = 0;
- s32 ret_val = E1000_SUCCESS;
DEBUGFUNC("e1000_write_phy_reg_mdic");
@@ -350,13 +372,11 @@ s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
}
if (!(mdic & E1000_MDIC_READY)) {
DEBUGOUT("MDI Write did not complete\n");
- ret_val = -E1000_ERR_PHY;
- goto out;
+ return -E1000_ERR_PHY;
}
if (mdic & E1000_MDIC_ERROR) {
DEBUGOUT("MDI Error\n");
- ret_val = -E1000_ERR_PHY;
- goto out;
+ return -E1000_ERR_PHY;
}
/*
@@ -366,8 +386,7 @@ s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
if (hw->mac.type == e1000_pch2lan)
usec_delay(100);
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -621,23 +640,22 @@ s32 e1000_write_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 data)
**/
s32 e1000_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data)
{
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
DEBUGFUNC("e1000_read_phy_reg_m88");
- if (!(hw->phy.ops.acquire))
- goto out;
+ if (!hw->phy.ops.acquire)
+ return E1000_SUCCESS;
ret_val = hw->phy.ops.acquire(hw);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
data);
hw->phy.ops.release(hw);
-out:
return ret_val;
}
@@ -652,23 +670,22 @@ out:
**/
s32 e1000_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data)
{
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
DEBUGFUNC("e1000_write_phy_reg_m88");
- if (!(hw->phy.ops.acquire))
- goto out;
+ if (!hw->phy.ops.acquire)
+ return E1000_SUCCESS;
ret_val = hw->phy.ops.acquire(hw);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
data);
hw->phy.ops.release(hw);
-out:
return ret_val;
}
@@ -711,29 +728,25 @@ static s32 __e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data,
DEBUGFUNC("__e1000_read_phy_reg_igp");
if (!locked) {
- if (!(hw->phy.ops.acquire))
- goto out;
+ if (!hw->phy.ops.acquire)
+ return E1000_SUCCESS;
ret_val = hw->phy.ops.acquire(hw);
if (ret_val)
- goto out;
+ return ret_val;
}
- if (offset > MAX_PHY_MULTI_PAGE_REG) {
+ if (offset > MAX_PHY_MULTI_PAGE_REG)
ret_val = e1000_write_phy_reg_mdic(hw,
IGP01E1000_PHY_PAGE_SELECT,
(u16)offset);
- if (ret_val)
- goto release;
- }
-
- ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
- data);
-
-release:
+ if (!ret_val)
+ ret_val = e1000_read_phy_reg_mdic(hw,
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
if (!locked)
hw->phy.ops.release(hw);
-out:
+
return ret_val;
}
@@ -784,30 +797,25 @@ static s32 __e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data,
DEBUGFUNC("e1000_write_phy_reg_igp");
if (!locked) {
- if (!(hw->phy.ops.acquire))
- goto out;
+ if (!hw->phy.ops.acquire)
+ return E1000_SUCCESS;
ret_val = hw->phy.ops.acquire(hw);
if (ret_val)
- goto out;
+ return ret_val;
}
- if (offset > MAX_PHY_MULTI_PAGE_REG) {
+ if (offset > MAX_PHY_MULTI_PAGE_REG)
ret_val = e1000_write_phy_reg_mdic(hw,
IGP01E1000_PHY_PAGE_SELECT,
(u16)offset);
- if (ret_val)
- goto release;
- }
-
- ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
- data);
-
-release:
+ if (!ret_val)
+ ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS &
+ offset,
+ data);
if (!locked)
hw->phy.ops.release(hw);
-out:
return ret_val;
}
@@ -854,17 +862,18 @@ static s32 __e1000_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data,
bool locked)
{
u32 kmrnctrlsta;
- s32 ret_val = E1000_SUCCESS;
DEBUGFUNC("__e1000_read_kmrn_reg");
if (!locked) {
- if (!(hw->phy.ops.acquire))
- goto out;
+ s32 ret_val = E1000_SUCCESS;
+
+ if (!hw->phy.ops.acquire)
+ return E1000_SUCCESS;
ret_val = hw->phy.ops.acquire(hw);
if (ret_val)
- goto out;
+ return ret_val;
}
kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
@@ -880,8 +889,7 @@ static s32 __e1000_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data,
if (!locked)
hw->phy.ops.release(hw);
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -929,17 +937,18 @@ static s32 __e1000_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data,
bool locked)
{
u32 kmrnctrlsta;
- s32 ret_val = E1000_SUCCESS;
DEBUGFUNC("e1000_write_kmrn_reg_generic");
if (!locked) {
- if (!(hw->phy.ops.acquire))
- goto out;
+ s32 ret_val = E1000_SUCCESS;
+
+ if (!hw->phy.ops.acquire)
+ return E1000_SUCCESS;
ret_val = hw->phy.ops.acquire(hw);
if (ret_val)
- goto out;
+ return ret_val;
}
kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
@@ -952,8 +961,7 @@ static s32 __e1000_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data,
if (!locked)
hw->phy.ops.release(hw);
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -985,6 +993,46 @@ s32 e1000_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data)
}
/**
+ * e1000_set_master_slave_mode - Setup PHY for Master/slave mode
+ * @hw: pointer to the HW structure
+ *
+ * Sets up Master/slave mode
+ **/
+static s32 e1000_set_master_slave_mode(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ u16 phy_data;
+
+ /* Resolve Master/Slave mode */
+ ret_val = hw->phy.ops.read_reg(hw, PHY_1000T_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* load defaults for future use */
+ hw->phy.original_ms_type = (phy_data & CR_1000T_MS_ENABLE) ?
+ ((phy_data & CR_1000T_MS_VALUE) ?
+ e1000_ms_force_master :
+ e1000_ms_force_slave) : e1000_ms_auto;
+
+ switch (hw->phy.ms_type) {
+ case e1000_ms_force_master:
+ phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+ break;
+ case e1000_ms_force_slave:
+ phy_data |= CR_1000T_MS_ENABLE;
+ phy_data &= ~(CR_1000T_MS_VALUE);
+ break;
+ case e1000_ms_auto:
+ phy_data &= ~CR_1000T_MS_ENABLE;
+ /* fall-through */
+ default:
+ break;
+ }
+
+ return hw->phy.ops.write_reg(hw, PHY_1000T_CTRL, phy_data);
+}
+
+/**
* e1000_copper_link_setup_82577 - Setup 82577 PHY for copper link
* @hw: pointer to the HW structure
*
@@ -1001,14 +1049,14 @@ s32 e1000_copper_link_setup_82577(struct e1000_hw *hw)
ret_val = hw->phy.ops.reset(hw);
if (ret_val) {
DEBUGOUT("Error resetting the PHY.\n");
- goto out;
+ return ret_val;
}
}
/* Enable CRS on Tx. This must be set for half-duplex operation. */
ret_val = hw->phy.ops.read_reg(hw, I82577_CFG_REG, &phy_data);
if (ret_val)
- goto out;
+ return ret_val;
phy_data |= I82577_CFG_ASSERT_CRS_ON_TX;
@@ -1017,39 +1065,35 @@ s32 e1000_copper_link_setup_82577(struct e1000_hw *hw)
ret_val = hw->phy.ops.write_reg(hw, I82577_CFG_REG, phy_data);
if (ret_val)
- goto out;
+ return ret_val;
- /* Resolve Master/Slave mode */
- ret_val = hw->phy.ops.read_reg(hw, PHY_1000T_CTRL, &phy_data);
+ /* Set MDI/MDIX mode */
+ ret_val = hw->phy.ops.read_reg(hw, I82577_PHY_CTRL_2, &phy_data);
if (ret_val)
- goto out;
-
- /* load defaults for future use */
- hw->phy.original_ms_type = (phy_data & CR_1000T_MS_ENABLE) ?
- ((phy_data & CR_1000T_MS_VALUE) ?
- e1000_ms_force_master :
- e1000_ms_force_slave) : e1000_ms_auto;
-
- switch (hw->phy.ms_type) {
- case e1000_ms_force_master:
- phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+ return ret_val;
+ phy_data &= ~I82577_PHY_CTRL2_MDIX_CFG_MASK;
+ /*
+ * Options:
+ * 0 - Auto (default)
+ * 1 - MDI mode
+ * 2 - MDI-X mode
+ */
+ switch (hw->phy.mdix) {
+ case 1:
break;
- case e1000_ms_force_slave:
- phy_data |= CR_1000T_MS_ENABLE;
- phy_data &= ~(CR_1000T_MS_VALUE);
+ case 2:
+ phy_data |= I82577_PHY_CTRL2_MANUAL_MDIX;
break;
- case e1000_ms_auto:
- phy_data &= ~CR_1000T_MS_ENABLE;
+ case 0:
default:
+ phy_data |= I82577_PHY_CTRL2_AUTO_MDI_MDIX;
break;
}
-
- ret_val = hw->phy.ops.write_reg(hw, PHY_1000T_CTRL, phy_data);
+ ret_val = hw->phy.ops.write_reg(hw, I82577_PHY_CTRL_2, phy_data);
if (ret_val)
- goto out;
+ return ret_val;
-out:
- return ret_val;
+ return e1000_set_master_slave_mode(hw);
}
/**
@@ -1071,7 +1115,7 @@ s32 e1000_copper_link_setup_m88(struct e1000_hw *hw)
/* Enable CRS on Tx. This must be set for half-duplex operation. */
ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
if (ret_val)
- goto out;
+ return ret_val;
/* For BM PHY this bit is downshift enable */
if (phy->type != e1000_phy_bm)
@@ -1111,16 +1155,32 @@ s32 e1000_copper_link_setup_m88(struct e1000_hw *hw)
* 1 - Enabled
*/
phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
- if (phy->disable_polarity_correction == 1)
+ if (phy->disable_polarity_correction)
phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
/* Enable downshift on BM (disabled by default) */
- if (phy->type == e1000_phy_bm)
+ if (phy->type == e1000_phy_bm) {
+ /* For 82574/82583, first disable then enable downshift */
+ if (phy->id == BME1000_E_PHY_ID_R2) {
+ phy_data &= ~BME1000_PSCR_ENABLE_DOWNSHIFT;
+ ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL,
+ phy_data);
+ if (ret_val)
+ return ret_val;
+ /* Commit the changes. */
+ ret_val = phy->ops.commit(hw);
+ if (ret_val) {
+ DEBUGOUT("Error committing the PHY changes\n");
+ return ret_val;
+ }
+ }
+
phy_data |= BME1000_PSCR_ENABLE_DOWNSHIFT;
+ }
ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
if (ret_val)
- goto out;
+ return ret_val;
if ((phy->type == e1000_phy_m88) &&
(phy->revision < E1000_REVISION_4) &&
@@ -1132,7 +1192,7 @@ s32 e1000_copper_link_setup_m88(struct e1000_hw *hw)
ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
&phy_data);
if (ret_val)
- goto out;
+ return ret_val;
phy_data |= M88E1000_EPSCR_TX_CLK_25;
@@ -1151,33 +1211,33 @@ s32 e1000_copper_link_setup_m88(struct e1000_hw *hw)
ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
phy_data);
if (ret_val)
- goto out;
+ 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 = phy->ops.write_reg(hw, 29, 0x0003);
if (ret_val)
- goto out;
+ return ret_val;
/* Set PHY page 0, register 30 to 0x0000 */
ret_val = phy->ops.write_reg(hw, 30, 0x0000);
if (ret_val)
- goto out;
+ return ret_val;
}
/* Commit the changes. */
ret_val = phy->ops.commit(hw);
if (ret_val) {
DEBUGOUT("Error committing the PHY changes\n");
- goto out;
+ return ret_val;
}
if (phy->type == e1000_phy_82578) {
ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
&phy_data);
if (ret_val)
- goto out;
+ return ret_val;
/* 82578 PHY - set the downshift count to 1x. */
phy_data |= I82578_EPSCR_DOWNSHIFT_ENABLE;
@@ -1185,11 +1245,16 @@ s32 e1000_copper_link_setup_m88(struct e1000_hw *hw)
ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
phy_data);
if (ret_val)
- goto out;
+ return ret_val;
}
-out:
- return ret_val;
+ if (phy->type == e1000_phy_i210) {
+ ret_val = e1000_set_master_slave_mode(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
+ return E1000_SUCCESS;
}
/**
@@ -1211,7 +1276,7 @@ s32 e1000_copper_link_setup_m88_gen2(struct e1000_hw *hw)
/* Enable CRS on Tx. This must be set for half-duplex operation. */
ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
if (ret_val)
- goto out;
+ return ret_val;
/*
* Options:
@@ -1250,7 +1315,7 @@ s32 e1000_copper_link_setup_m88_gen2(struct e1000_hw *hw)
* 1 - Enabled
*/
phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
- if (phy->disable_polarity_correction == 1)
+ if (phy->disable_polarity_correction)
phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
/* Enable downshift and setting it to X6 */
@@ -1260,17 +1325,16 @@ s32 e1000_copper_link_setup_m88_gen2(struct e1000_hw *hw)
ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
if (ret_val)
- goto out;
+ return ret_val;
/* Commit the changes. */
ret_val = phy->ops.commit(hw);
if (ret_val) {
DEBUGOUT("Error committing the PHY changes\n");
- goto out;
+ return ret_val;
}
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -1292,7 +1356,7 @@ s32 e1000_copper_link_setup_igp(struct e1000_hw *hw)
ret_val = hw->phy.ops.reset(hw);
if (ret_val) {
DEBUGOUT("Error resetting the PHY.\n");
- goto out;
+ return ret_val;
}
/*
@@ -1310,7 +1374,7 @@ s32 e1000_copper_link_setup_igp(struct e1000_hw *hw)
ret_val = hw->phy.ops.set_d3_lplu_state(hw, FALSE);
if (ret_val) {
DEBUGOUT("Error Disabling LPLU D3\n");
- goto out;
+ return ret_val;
}
}
@@ -1319,13 +1383,13 @@ s32 e1000_copper_link_setup_igp(struct e1000_hw *hw)
ret_val = hw->phy.ops.set_d0_lplu_state(hw, FALSE);
if (ret_val) {
DEBUGOUT("Error Disabling LPLU D0\n");
- goto out;
+ return ret_val;
}
}
/* Configure mdi-mdix settings */
ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &data);
if (ret_val)
- goto out;
+ return ret_val;
data &= ~IGP01E1000_PSCR_AUTO_MDIX;
@@ -1343,7 +1407,7 @@ s32 e1000_copper_link_setup_igp(struct e1000_hw *hw)
}
ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, data);
if (ret_val)
- goto out;
+ return ret_val;
/* set auto-master slave resolution settings */
if (hw->mac.autoneg) {
@@ -1358,125 +1422,29 @@ s32 e1000_copper_link_setup_igp(struct e1000_hw *hw)
IGP01E1000_PHY_PORT_CONFIG,
&data);
if (ret_val)
- goto out;
+ return ret_val;
data &= ~IGP01E1000_PSCFR_SMART_SPEED;
ret_val = phy->ops.write_reg(hw,
IGP01E1000_PHY_PORT_CONFIG,
data);
if (ret_val)
- goto out;
+ return ret_val;
/* Set auto Master/Slave resolution process */
ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
if (ret_val)
- goto out;
+ return ret_val;
data &= ~CR_1000T_MS_ENABLE;
ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
if (ret_val)
- goto out;
+ return ret_val;
}
- ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
- if (ret_val)
- goto out;
-
- /* load defaults for future use */
- phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ?
- ((data & CR_1000T_MS_VALUE) ?
- e1000_ms_force_master :
- e1000_ms_force_slave) :
- e1000_ms_auto;
-
- switch (phy->ms_type) {
- case e1000_ms_force_master:
- data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
- break;
- case e1000_ms_force_slave:
- data |= CR_1000T_MS_ENABLE;
- data &= ~(CR_1000T_MS_VALUE);
- break;
- case e1000_ms_auto:
- data &= ~CR_1000T_MS_ENABLE;
- default:
- break;
- }
- ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
- if (ret_val)
- goto out;
+ ret_val = e1000_set_master_slave_mode(hw);
}
-out:
- return ret_val;
-}
-
-/**
- * e1000_copper_link_autoneg - Setup/Enable autoneg for copper link
- * @hw: pointer to the HW structure
- *
- * Performs initial bounds checking on autoneg advertisement parameter, then
- * configure to advertise the full capability. Setup the PHY to autoneg
- * and restart the negotiation process between the link partner. If
- * autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
- **/
-s32 e1000_copper_link_autoneg(struct e1000_hw *hw)
-{
- struct e1000_phy_info *phy = &hw->phy;
- s32 ret_val;
- u16 phy_ctrl;
-
- DEBUGFUNC("e1000_copper_link_autoneg");
-
- /*
- * Perform some bounds checking on the autoneg advertisement
- * parameter.
- */
- phy->autoneg_advertised &= phy->autoneg_mask;
-
- /*
- * If autoneg_advertised is zero, we assume it was not defaulted
- * by the calling code so we set to advertise full capability.
- */
- if (phy->autoneg_advertised == 0)
- phy->autoneg_advertised = phy->autoneg_mask;
-
- DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
- ret_val = e1000_phy_setup_autoneg(hw);
- if (ret_val) {
- DEBUGOUT("Error Setting up Auto-Negotiation\n");
- goto out;
- }
- DEBUGOUT("Restarting Auto-Neg\n");
-
- /*
- * Restart auto-negotiation by setting the Auto Neg Enable bit and
- * the Auto Neg Restart bit in the PHY control register.
- */
- ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
- if (ret_val)
- goto out;
-
- phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
- ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
- if (ret_val)
- goto out;
-
- /*
- * Does the user want to wait for Auto-Neg to complete here, or
- * check at a later time (for example, callback routine).
- */
- if (phy->autoneg_wait_to_complete) {
- ret_val = hw->mac.ops.wait_autoneg(hw);
- if (ret_val) {
- DEBUGOUT("Error while waiting for autoneg to complete\n");
- goto out;
- }
- }
-
- hw->mac.get_link_status = TRUE;
-
-out:
return ret_val;
}
@@ -1503,14 +1471,14 @@ s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
/* Read the MII Auto-Neg Advertisement Register (Address 4). */
ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
if (ret_val)
- goto out;
+ return ret_val;
if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
/* Read the MII 1000Base-T Control Register (Address 9). */
ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL,
&mii_1000t_ctrl_reg);
if (ret_val)
- goto out;
+ return ret_val;
}
/*
@@ -1624,24 +1592,87 @@ s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
break;
default:
DEBUGOUT("Flow control param set incorrectly\n");
- ret_val = -E1000_ERR_CONFIG;
- goto out;
+ return -E1000_ERR_CONFIG;
}
ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
if (ret_val)
- goto out;
+ return ret_val;
DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
- if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+ if (phy->autoneg_mask & ADVERTISE_1000_FULL)
ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL,
mii_1000t_ctrl_reg);
- if (ret_val)
- goto out;
+
+ return ret_val;
+}
+
+/**
+ * e1000_copper_link_autoneg - Setup/Enable autoneg for copper link
+ * @hw: pointer to the HW structure
+ *
+ * Performs initial bounds checking on autoneg advertisement parameter, then
+ * configure to advertise the full capability. Setup the PHY to autoneg
+ * and restart the negotiation process between the link partner. If
+ * autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
+ **/
+s32 e1000_copper_link_autoneg(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_ctrl;
+
+ DEBUGFUNC("e1000_copper_link_autoneg");
+
+ /*
+ * Perform some bounds checking on the autoneg advertisement
+ * parameter.
+ */
+ phy->autoneg_advertised &= phy->autoneg_mask;
+
+ /*
+ * If autoneg_advertised is zero, we assume it was not defaulted
+ * by the calling code so we set to advertise full capability.
+ */
+ if (!phy->autoneg_advertised)
+ phy->autoneg_advertised = phy->autoneg_mask;
+
+ DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
+ ret_val = e1000_phy_setup_autoneg(hw);
+ if (ret_val) {
+ DEBUGOUT("Error Setting up Auto-Negotiation\n");
+ return ret_val;
}
+ DEBUGOUT("Restarting Auto-Neg\n");
+
+ /*
+ * Restart auto-negotiation by setting the Auto Neg Enable bit and
+ * the Auto Neg Restart bit in the PHY control register.
+ */
+ ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
+ if (ret_val)
+ return ret_val;
+
+ phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+ ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
+ if (ret_val)
+ return ret_val;
+
+ /*
+ * Does the user want to wait for Auto-Neg to complete here, or
+ * check at a later time (for example, callback routine).
+ */
+ if (phy->autoneg_wait_to_complete) {
+ ret_val = hw->mac.ops.wait_autoneg(hw);
+ if (ret_val) {
+ DEBUGOUT("Error while waiting for autoneg to complete\n");
+ return ret_val;
+ }
+ }
+
+ hw->mac.get_link_status = TRUE;
-out:
return ret_val;
}
@@ -1668,7 +1699,7 @@ s32 e1000_setup_copper_link_generic(struct e1000_hw *hw)
*/
ret_val = e1000_copper_link_autoneg(hw);
if (ret_val)
- goto out;
+ return ret_val;
} else {
/*
* PHY will be set to 10H, 10F, 100H or 100F
@@ -1678,7 +1709,7 @@ s32 e1000_setup_copper_link_generic(struct e1000_hw *hw)
ret_val = hw->phy.ops.force_speed_duplex(hw);
if (ret_val) {
DEBUGOUT("Error Forcing Speed and Duplex\n");
- goto out;
+ return ret_val;
}
}
@@ -1689,17 +1720,16 @@ s32 e1000_setup_copper_link_generic(struct e1000_hw *hw)
ret_val = e1000_phy_has_link_generic(hw, COPPER_LINK_UP_LIMIT, 10,
&link);
if (ret_val)
- goto out;
+ return ret_val;
if (link) {
DEBUGOUT("Valid link established!!!\n");
- e1000_config_collision_dist_generic(hw);
+ hw->mac.ops.config_collision_dist(hw);
ret_val = e1000_config_fc_after_link_up_generic(hw);
} else {
DEBUGOUT("Unable to establish link!!!\n");
}
-out:
return ret_val;
}
@@ -1722,13 +1752,13 @@ s32 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw)
ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
if (ret_val)
- goto out;
+ return ret_val;
e1000_phy_force_speed_duplex_setup(hw, &phy_data);
ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
if (ret_val)
- goto out;
+ return ret_val;
/*
* Clear Auto-Crossover to force MDI manually. IGP requires MDI
@@ -1736,14 +1766,14 @@ s32 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw)
*/
ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
if (ret_val)
- goto out;
+ return ret_val;
phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
if (ret_val)
- goto out;
+ return ret_val;
DEBUGOUT1("IGP PSCR: %X\n", phy_data);
@@ -1755,7 +1785,7 @@ s32 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw)
ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
100000, &link);
if (ret_val)
- goto out;
+ return ret_val;
if (!link)
DEBUGOUT("Link taking longer than expected.\n");
@@ -1763,11 +1793,8 @@ s32 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw)
/* Try once more */
ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
100000, &link);
- if (ret_val)
- goto out;
}
-out:
return ret_val;
}
@@ -1796,29 +1823,29 @@ s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw)
*/
ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
if (ret_val)
- goto out;
+ return ret_val;
phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
if (ret_val)
- goto out;
+ return ret_val;
DEBUGOUT1("M88E1000 PSCR: %X\n", phy_data);
ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
if (ret_val)
- goto out;
+ return ret_val;
e1000_phy_force_speed_duplex_setup(hw, &phy_data);
ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
if (ret_val)
- goto out;
+ return ret_val;
/* Reset the phy to commit changes. */
ret_val = hw->phy.ops.commit(hw);
if (ret_val)
- goto out;
+ return ret_val;
if (phy->autoneg_wait_to_complete) {
DEBUGOUT("Waiting for forced speed/duplex link on M88 phy.\n");
@@ -1826,13 +1853,25 @@ s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw)
ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
100000, &link);
if (ret_val)
- goto out;
+ return ret_val;
if (!link) {
- if (hw->phy.type != e1000_phy_m88 ||
- hw->phy.id == I347AT4_E_PHY_ID ||
- hw->phy.id == M88E1340M_E_PHY_ID ||
- hw->phy.id == M88E1112_E_PHY_ID) {
+ bool reset_dsp = TRUE;
+
+ switch (hw->phy.id) {
+ case I347AT4_E_PHY_ID:
+ case M88E1340M_E_PHY_ID:
+ case M88E1112_E_PHY_ID:
+ case I210_I_PHY_ID:
+ reset_dsp = FALSE;
+ break;
+ default:
+ if (hw->phy.type != e1000_phy_m88)
+ reset_dsp = FALSE;
+ break;
+ }
+
+ if (!reset_dsp) {
DEBUGOUT("Link taking longer than expected.\n");
} else {
/*
@@ -1843,10 +1882,10 @@ s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw)
M88E1000_PHY_PAGE_SELECT,
0x001d);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = e1000_phy_reset_dsp_generic(hw);
if (ret_val)
- goto out;
+ return ret_val;
}
}
@@ -1854,18 +1893,21 @@ s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw)
ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
100000, &link);
if (ret_val)
- goto out;
+ return ret_val;
}
- if (hw->phy.type != e1000_phy_m88 ||
- hw->phy.id == I347AT4_E_PHY_ID ||
- hw->phy.id == M88E1340M_E_PHY_ID ||
- hw->phy.id == M88E1112_E_PHY_ID)
- goto out;
+ if (hw->phy.type != e1000_phy_m88)
+ return E1000_SUCCESS;
+ if (hw->phy.id == I347AT4_E_PHY_ID ||
+ hw->phy.id == M88E1340M_E_PHY_ID ||
+ hw->phy.id == M88E1112_E_PHY_ID)
+ return E1000_SUCCESS;
+ if (hw->phy.id == I210_I_PHY_ID)
+ return E1000_SUCCESS;
ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
if (ret_val)
- goto out;
+ return ret_val;
/*
* Resetting the phy means we need to re-force TX_CLK in the
@@ -1875,7 +1917,7 @@ s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw)
phy_data |= M88E1000_EPSCR_TX_CLK_25;
ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
if (ret_val)
- goto out;
+ return ret_val;
/*
* In addition, we must re-enable CRS on Tx for both half and full
@@ -1883,12 +1925,11 @@ s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw)
*/
ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
if (ret_val)
- goto out;
+ return ret_val;
phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
-out:
return ret_val;
}
@@ -1911,25 +1952,25 @@ s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw)
ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &data);
if (ret_val)
- goto out;
+ return ret_val;
e1000_phy_force_speed_duplex_setup(hw, &data);
ret_val = phy->ops.write_reg(hw, PHY_CONTROL, data);
if (ret_val)
- goto out;
+ return ret_val;
/* Disable MDI-X support for 10/100 */
ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data);
if (ret_val)
- goto out;
+ return ret_val;
data &= ~IFE_PMC_AUTO_MDIX;
data &= ~IFE_PMC_FORCE_MDIX;
ret_val = phy->ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, data);
if (ret_val)
- goto out;
+ return ret_val;
DEBUGOUT1("IFE PMC: %X\n", data);
@@ -1941,7 +1982,7 @@ s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw)
ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
100000, &link);
if (ret_val)
- goto out;
+ return ret_val;
if (!link)
DEBUGOUT("Link taking longer than expected.\n");
@@ -1950,11 +1991,10 @@ s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw)
ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
100000, &link);
if (ret_val)
- goto out;
+ return ret_val;
}
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -2014,7 +2054,7 @@ void e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl)
DEBUGOUT("Forcing 10mb\n");
}
- e1000_config_collision_dist_generic(hw);
+ hw->mac.ops.config_collision_dist(hw);
E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
}
@@ -2036,24 +2076,24 @@ void e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl)
s32 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active)
{
struct e1000_phy_info *phy = &hw->phy;
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
u16 data;
DEBUGFUNC("e1000_set_d3_lplu_state_generic");
- if (!(hw->phy.ops.read_reg))
- goto out;
+ if (!hw->phy.ops.read_reg)
+ return E1000_SUCCESS;
ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
if (ret_val)
- goto out;
+ return ret_val;
if (!active) {
data &= ~IGP02E1000_PM_D3_LPLU;
ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
data);
if (ret_val)
- goto out;
+ return ret_val;
/*
* LPLU and SmartSpeed are mutually exclusive. LPLU is used
* during Dx states where the power conservation is most
@@ -2065,27 +2105,27 @@ s32 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active)
IGP01E1000_PHY_PORT_CONFIG,
&data);
if (ret_val)
- goto out;
+ return ret_val;
data |= IGP01E1000_PSCFR_SMART_SPEED;
ret_val = phy->ops.write_reg(hw,
IGP01E1000_PHY_PORT_CONFIG,
data);
if (ret_val)
- goto out;
+ return ret_val;
} else if (phy->smart_speed == e1000_smart_speed_off) {
ret_val = phy->ops.read_reg(hw,
IGP01E1000_PHY_PORT_CONFIG,
&data);
if (ret_val)
- goto out;
+ return ret_val;
data &= ~IGP01E1000_PSCFR_SMART_SPEED;
ret_val = phy->ops.write_reg(hw,
IGP01E1000_PHY_PORT_CONFIG,
data);
if (ret_val)
- goto out;
+ return ret_val;
}
} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
(phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
@@ -2094,20 +2134,19 @@ s32 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active)
ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
data);
if (ret_val)
- goto out;
+ return ret_val;
/* When LPLU is enabled, we should disable SmartSpeed */
ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
&data);
if (ret_val)
- goto out;
+ return ret_val;
data &= ~IGP01E1000_PSCFR_SMART_SPEED;
ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
data);
}
-out:
return ret_val;
}
@@ -2128,6 +2167,7 @@ s32 e1000_check_downshift_generic(struct e1000_hw *hw)
DEBUGFUNC("e1000_check_downshift_generic");
switch (phy->type) {
+ case e1000_phy_i210:
case e1000_phy_m88:
case e1000_phy_gg82563:
case e1000_phy_bm:
@@ -2144,16 +2184,14 @@ s32 e1000_check_downshift_generic(struct e1000_hw *hw)
default:
/* speed downshift not supported */
phy->speed_downgraded = FALSE;
- ret_val = E1000_SUCCESS;
- goto out;
+ return E1000_SUCCESS;
}
ret_val = phy->ops.read_reg(hw, offset, &phy_data);
if (!ret_val)
- phy->speed_downgraded = (phy_data & mask) ? TRUE : FALSE;
+ phy->speed_downgraded = !!(phy_data & mask);
-out:
return ret_val;
}
@@ -2206,7 +2244,7 @@ s32 e1000_check_polarity_igp(struct e1000_hw *hw)
*/
ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
if (ret_val)
- goto out;
+ return ret_val;
if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
IGP01E1000_PSSR_SPEED_1000MBPS) {
@@ -2228,7 +2266,6 @@ s32 e1000_check_polarity_igp(struct e1000_hw *hw)
? e1000_rev_polarity_reversed
: e1000_rev_polarity_normal;
-out:
return ret_val;
}
@@ -2281,7 +2318,7 @@ s32 e1000_wait_autoneg_generic(struct e1000_hw *hw)
DEBUGFUNC("e1000_wait_autoneg_generic");
- if (!(hw->phy.ops.read_reg))
+ if (!hw->phy.ops.read_reg)
return E1000_SUCCESS;
/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
@@ -2321,7 +2358,7 @@ s32 e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
DEBUGFUNC("e1000_phy_has_link_generic");
- if (!(hw->phy.ops.read_reg))
+ if (!hw->phy.ops.read_reg)
return E1000_SUCCESS;
for (i = 0; i < iterations; i++) {
@@ -2349,7 +2386,7 @@ s32 e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
usec_delay(usec_interval);
}
- *success = (i < iterations) ? TRUE : FALSE;
+ *success = (i < iterations);
return ret_val;
}
@@ -2379,22 +2416,20 @@ s32 e1000_get_cable_length_m88(struct e1000_hw *hw)
ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
if (ret_val)
- goto out;
+ return ret_val;
index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
M88E1000_PSSR_CABLE_LENGTH_SHIFT;
- if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) {
- ret_val = -E1000_ERR_PHY;
- goto out;
- }
+
+ if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1)
+ return -E1000_ERR_PHY;
phy->min_cable_length = e1000_m88_cable_length_table[index];
phy->max_cable_length = e1000_m88_cable_length_table[index + 1];
phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
s32 e1000_get_cable_length_m88_gen2(struct e1000_hw *hw)
@@ -2406,28 +2441,49 @@ s32 e1000_get_cable_length_m88_gen2(struct e1000_hw *hw)
DEBUGFUNC("e1000_get_cable_length_m88_gen2");
switch (hw->phy.id) {
+ case I210_I_PHY_ID:
+ /* Get cable length from PHY Cable Diagnostics Control Reg */
+ ret_val = phy->ops.read_reg(hw, (0x7 << GS40G_PAGE_SHIFT) +
+ (I347AT4_PCDL + phy->addr),
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Check if the unit of cable length is meters or cm */
+ ret_val = phy->ops.read_reg(hw, (0x7 << GS40G_PAGE_SHIFT) +
+ I347AT4_PCDC, &phy_data2);
+ if (ret_val)
+ return ret_val;
+
+ is_cm = !(phy_data2 & I347AT4_PCDC_CABLE_LENGTH_UNIT);
+
+ /* Populate the phy structure with cable length in meters */
+ phy->min_cable_length = phy_data / (is_cm ? 100 : 1);
+ phy->max_cable_length = phy_data / (is_cm ? 100 : 1);
+ phy->cable_length = phy_data / (is_cm ? 100 : 1);
+ break;
case M88E1340M_E_PHY_ID:
case I347AT4_E_PHY_ID:
/* Remember the original page select and set it to 7 */
ret_val = phy->ops.read_reg(hw, I347AT4_PAGE_SELECT,
&default_page);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, 0x07);
if (ret_val)
- goto out;
+ return ret_val;
/* Get cable length from PHY Cable Diagnostics Control Reg */
ret_val = phy->ops.read_reg(hw, (I347AT4_PCDL + phy->addr),
&phy_data);
if (ret_val)
- goto out;
+ return ret_val;
/* Check if the unit of cable length is meters or cm */
ret_val = phy->ops.read_reg(hw, I347AT4_PCDC, &phy_data2);
if (ret_val)
- goto out;
+ return ret_val;
is_cm = !(phy_data2 & I347AT4_PCDC_CABLE_LENGTH_UNIT);
@@ -2440,30 +2496,30 @@ s32 e1000_get_cable_length_m88_gen2(struct e1000_hw *hw)
ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT,
default_page);
if (ret_val)
- goto out;
+ return ret_val;
break;
+
case M88E1112_E_PHY_ID:
/* Remember the original page select and set it to 5 */
ret_val = phy->ops.read_reg(hw, I347AT4_PAGE_SELECT,
&default_page);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, 0x05);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = phy->ops.read_reg(hw, M88E1112_VCT_DSP_DISTANCE,
&phy_data);
if (ret_val)
- goto out;
+ return ret_val;
index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
M88E1000_PSSR_CABLE_LENGTH_SHIFT;
- if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) {
- ret_val = -E1000_ERR_PHY;
- goto out;
- }
+
+ if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1)
+ return -E1000_ERR_PHY;
phy->min_cable_length = e1000_m88_cable_length_table[index];
phy->max_cable_length = e1000_m88_cable_length_table[index + 1];
@@ -2475,15 +2531,13 @@ s32 e1000_get_cable_length_m88_gen2(struct e1000_hw *hw)
ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT,
default_page);
if (ret_val)
- goto out;
+ return ret_val;
break;
default:
- ret_val = -E1000_ERR_PHY;
- goto out;
+ return -E1000_ERR_PHY;
}
-out:
return ret_val;
}
@@ -2501,7 +2555,7 @@ out:
s32 e1000_get_cable_length_igp_2(struct e1000_hw *hw)
{
struct e1000_phy_info *phy = &hw->phy;
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
u16 phy_data, i, agc_value = 0;
u16 cur_agc_index, max_agc_index = 0;
u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;
@@ -2518,7 +2572,7 @@ s32 e1000_get_cable_length_igp_2(struct e1000_hw *hw)
for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &phy_data);
if (ret_val)
- goto out;
+ return ret_val;
/*
* Getting bits 15:9, which represent the combination of
@@ -2531,10 +2585,8 @@ s32 e1000_get_cable_length_igp_2(struct e1000_hw *hw)
/* Array index bound check. */
if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
- (cur_agc_index == 0)) {
- ret_val = -E1000_ERR_PHY;
- goto out;
- }
+ (cur_agc_index == 0))
+ return -E1000_ERR_PHY;
/* Remove min & max AGC values from calculation. */
if (e1000_igp_2_cable_length_table[min_agc_index] >
@@ -2558,8 +2610,7 @@ s32 e1000_get_cable_length_igp_2(struct e1000_hw *hw)
phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -2583,45 +2634,43 @@ s32 e1000_get_phy_info_m88(struct e1000_hw *hw)
if (phy->media_type != e1000_media_type_copper) {
DEBUGOUT("Phy info is only valid for copper media\n");
- ret_val = -E1000_ERR_CONFIG;
- goto out;
+ return -E1000_ERR_CONFIG;
}
ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
if (ret_val)
- goto out;
+ return ret_val;
if (!link) {
DEBUGOUT("Phy info is only valid if link is up\n");
- ret_val = -E1000_ERR_CONFIG;
- goto out;
+ return -E1000_ERR_CONFIG;
}
ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
if (ret_val)
- goto out;
+ return ret_val;
- phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL)
- ? TRUE : FALSE;
+ phy->polarity_correction = !!(phy_data &
+ M88E1000_PSCR_POLARITY_REVERSAL);
ret_val = e1000_check_polarity_m88(hw);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
if (ret_val)
- goto out;
+ return ret_val;
- phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? TRUE : FALSE;
+ phy->is_mdix = !!(phy_data & M88E1000_PSSR_MDIX);
if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
ret_val = hw->phy.ops.get_cable_length(hw);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data);
if (ret_val)
- goto out;
+ return ret_val;
phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
? e1000_1000t_rx_status_ok
@@ -2637,7 +2686,6 @@ s32 e1000_get_phy_info_m88(struct e1000_hw *hw)
phy->remote_rx = e1000_1000t_rx_status_undefined;
}
-out:
return ret_val;
}
@@ -2661,35 +2709,34 @@ s32 e1000_get_phy_info_igp(struct e1000_hw *hw)
ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
if (ret_val)
- goto out;
+ return ret_val;
if (!link) {
DEBUGOUT("Phy info is only valid if link is up\n");
- ret_val = -E1000_ERR_CONFIG;
- goto out;
+ return -E1000_ERR_CONFIG;
}
phy->polarity_correction = TRUE;
ret_val = e1000_check_polarity_igp(hw);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
if (ret_val)
- goto out;
+ return ret_val;
- phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? TRUE : FALSE;
+ phy->is_mdix = !!(data & IGP01E1000_PSSR_MDIX);
if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
IGP01E1000_PSSR_SPEED_1000MBPS) {
ret_val = phy->ops.get_cable_length(hw);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data);
if (ret_val)
- goto out;
+ return ret_val;
phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
? e1000_1000t_rx_status_ok
@@ -2704,7 +2751,6 @@ s32 e1000_get_phy_info_igp(struct e1000_hw *hw)
phy->remote_rx = e1000_1000t_rx_status_undefined;
}
-out:
return ret_val;
}
@@ -2725,24 +2771,22 @@ s32 e1000_get_phy_info_ife(struct e1000_hw *hw)
ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
if (ret_val)
- goto out;
+ return ret_val;
if (!link) {
DEBUGOUT("Phy info is only valid if link is up\n");
- ret_val = -E1000_ERR_CONFIG;
- goto out;
+ return -E1000_ERR_CONFIG;
}
ret_val = phy->ops.read_reg(hw, IFE_PHY_SPECIAL_CONTROL, &data);
if (ret_val)
- goto out;
- phy->polarity_correction = (data & IFE_PSC_AUTO_POLARITY_DISABLE)
- ? FALSE : TRUE;
+ return ret_val;
+ phy->polarity_correction = !(data & IFE_PSC_AUTO_POLARITY_DISABLE);
if (phy->polarity_correction) {
ret_val = e1000_check_polarity_ife(hw);
if (ret_val)
- goto out;
+ return ret_val;
} else {
/* Polarity is forced */
phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY)
@@ -2752,17 +2796,16 @@ s32 e1000_get_phy_info_ife(struct e1000_hw *hw)
ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data);
if (ret_val)
- goto out;
+ return ret_val;
- phy->is_mdix = (data & IFE_PMC_MDIX_STATUS) ? TRUE : FALSE;
+ 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;
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -2774,26 +2817,25 @@ out:
**/
s32 e1000_phy_sw_reset_generic(struct e1000_hw *hw)
{
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
u16 phy_ctrl;
DEBUGFUNC("e1000_phy_sw_reset_generic");
- if (!(hw->phy.ops.read_reg))
- goto out;
+ if (!hw->phy.ops.read_reg)
+ return E1000_SUCCESS;
ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
if (ret_val)
- goto out;
+ return ret_val;
phy_ctrl |= MII_CR_RESET;
ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
if (ret_val)
- goto out;
+ return ret_val;
usec_delay(1);
-out:
return ret_val;
}
@@ -2809,20 +2851,20 @@ out:
s32 e1000_phy_hw_reset_generic(struct e1000_hw *hw)
{
struct e1000_phy_info *phy = &hw->phy;
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
u32 ctrl;
DEBUGFUNC("e1000_phy_hw_reset_generic");
- ret_val = phy->ops.check_reset_block(hw);
- if (ret_val) {
- ret_val = E1000_SUCCESS;
- goto out;
+ if (phy->ops.check_reset_block) {
+ ret_val = phy->ops.check_reset_block(hw);
+ if (ret_val)
+ return E1000_SUCCESS;
}
ret_val = phy->ops.acquire(hw);
if (ret_val)
- goto out;
+ return ret_val;
ctrl = E1000_READ_REG(hw, E1000_CTRL);
E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PHY_RST);
@@ -2837,10 +2879,7 @@ s32 e1000_phy_hw_reset_generic(struct e1000_hw *hw)
phy->ops.release(hw);
- ret_val = phy->ops.get_cfg_done(hw);
-
-out:
- return ret_val;
+ return phy->ops.get_cfg_done(hw);
}
/**
@@ -2994,6 +3033,9 @@ enum e1000_phy_type e1000_get_phy_type_from_id(u32 phy_id)
case I82580_I_PHY_ID:
phy_type = e1000_phy_82580;
break;
+ case I210_I_PHY_ID:
+ phy_type = e1000_phy_i210;
+ break;
default:
phy_type = e1000_phy_unknown;
break;
@@ -3011,7 +3053,6 @@ enum e1000_phy_type e1000_get_phy_type_from_id(u32 phy_id)
**/
s32 e1000_determine_phy_address(struct e1000_hw *hw)
{
- s32 ret_val = -E1000_ERR_PHY_TYPE;
u32 phy_addr = 0;
u32 i;
enum e1000_phy_type phy_type = e1000_phy_unknown;
@@ -3030,17 +3071,15 @@ s32 e1000_determine_phy_address(struct e1000_hw *hw)
* If phy_type is valid, break - we found our
* PHY address
*/
- if (phy_type != e1000_phy_unknown) {
- ret_val = E1000_SUCCESS;
- goto out;
- }
+ if (phy_type != e1000_phy_unknown)
+ return E1000_SUCCESS;
+
msec_delay(1);
i++;
} while (i < 10);
}
-out:
- return ret_val;
+ return -E1000_ERR_PHY_TYPE;
}
/**
@@ -3083,7 +3122,7 @@ s32 e1000_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data)
if (page == BM_WUC_PAGE) {
ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data,
FALSE, FALSE);
- goto out;
+ goto release;
}
hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset);
@@ -3108,13 +3147,13 @@ s32 e1000_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data)
ret_val = e1000_write_phy_reg_mdic(hw, page_select,
(page << page_shift));
if (ret_val)
- goto out;
+ goto release;
}
ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
data);
-out:
+release:
hw->phy.ops.release(hw);
return ret_val;
}
@@ -3144,7 +3183,7 @@ s32 e1000_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data)
if (page == BM_WUC_PAGE) {
ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data,
TRUE, FALSE);
- goto out;
+ goto release;
}
hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset);
@@ -3169,12 +3208,12 @@ s32 e1000_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data)
ret_val = e1000_write_phy_reg_mdic(hw, page_select,
(page << page_shift));
if (ret_val)
- goto out;
+ goto release;
}
ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
data);
-out:
+release:
hw->phy.ops.release(hw);
return ret_val;
}
@@ -3204,7 +3243,7 @@ s32 e1000_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data)
if (page == BM_WUC_PAGE) {
ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data,
TRUE, FALSE);
- goto out;
+ goto release;
}
hw->phy.addr = 1;
@@ -3216,12 +3255,12 @@ s32 e1000_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data)
page);
if (ret_val)
- goto out;
+ goto release;
}
ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
data);
-out:
+release:
hw->phy.ops.release(hw);
return ret_val;
}
@@ -3250,7 +3289,7 @@ s32 e1000_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data)
if (page == BM_WUC_PAGE) {
ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data,
FALSE, FALSE);
- goto out;
+ goto release;
}
hw->phy.addr = 1;
@@ -3261,13 +3300,13 @@ s32 e1000_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data)
page);
if (ret_val)
- goto out;
+ goto release;
}
ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
data);
-out:
+release:
hw->phy.ops.release(hw);
return ret_val;
}
@@ -3287,10 +3326,8 @@ s32 e1000_enable_phy_wakeup_reg_access_bm(struct e1000_hw *hw, u16 *phy_reg)
DEBUGFUNC("e1000_enable_phy_wakeup_reg_access_bm");
- if (!phy_reg) {
- ret_val = -E1000_ERR_PARAM;
- goto out;
- }
+ if (!phy_reg)
+ return -E1000_ERR_PARAM;
/* All page select, port ctrl and wakeup registers use phy address 1 */
hw->phy.addr = 1;
@@ -3299,14 +3336,14 @@ s32 e1000_enable_phy_wakeup_reg_access_bm(struct e1000_hw *hw, u16 *phy_reg)
ret_val = e1000_set_page_igp(hw, (BM_PORT_CTRL_PAGE << IGP_PAGE_SHIFT));
if (ret_val) {
DEBUGOUT("Could not set Port Control page\n");
- goto out;
+ return ret_val;
}
ret_val = e1000_read_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);
if (ret_val) {
DEBUGOUT2("Could not read PHY register %d.%d\n",
BM_PORT_CTRL_PAGE, BM_WUC_ENABLE_REG);
- goto out;
+ return ret_val;
}
/*
@@ -3321,15 +3358,14 @@ s32 e1000_enable_phy_wakeup_reg_access_bm(struct e1000_hw *hw, u16 *phy_reg)
if (ret_val) {
DEBUGOUT2("Could not write PHY register %d.%d\n",
BM_PORT_CTRL_PAGE, BM_WUC_ENABLE_REG);
- goto out;
+ return ret_val;
}
- /* Select Host Wakeup Registers page */
- ret_val = e1000_set_page_igp(hw, (BM_WUC_PAGE << IGP_PAGE_SHIFT));
-
- /* caller now able to write registers on the Wakeup registers page */
-out:
- return ret_val;
+ /*
+ * Select Host Wakeup Registers page - caller now able to write
+ * registers on the Wakeup registers page
+ */
+ return e1000_set_page_igp(hw, (BM_WUC_PAGE << IGP_PAGE_SHIFT));
}
/**
@@ -3356,7 +3392,7 @@ s32 e1000_disable_phy_wakeup_reg_access_bm(struct e1000_hw *hw, u16 *phy_reg)
ret_val = e1000_set_page_igp(hw, (BM_PORT_CTRL_PAGE << IGP_PAGE_SHIFT));
if (ret_val) {
DEBUGOUT("Could not set Port Control page\n");
- goto out;
+ return ret_val;
}
/* Restore 769.17 to its original value */
@@ -3364,7 +3400,7 @@ s32 e1000_disable_phy_wakeup_reg_access_bm(struct e1000_hw *hw, u16 *phy_reg)
if (ret_val)
DEBUGOUT2("Could not restore PHY register %d.%d\n",
BM_PORT_CTRL_PAGE, BM_WUC_ENABLE_REG);
-out:
+
return ret_val;
}
@@ -3413,7 +3449,7 @@ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
ret_val = e1000_enable_phy_wakeup_reg_access_bm(hw, &phy_reg);
if (ret_val) {
DEBUGOUT("Could not enable PHY wakeup reg access\n");
- goto out;
+ return ret_val;
}
}
@@ -3423,7 +3459,7 @@ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ADDRESS_OPCODE, reg);
if (ret_val) {
DEBUGOUT1("Could not write address opcode to page %d\n", page);
- goto out;
+ return ret_val;
}
if (read) {
@@ -3438,13 +3474,12 @@ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
if (ret_val) {
DEBUGOUT2("Could not access PHY reg %d.%d\n", page, reg);
- goto out;
+ return ret_val;
}
if (!page_set)
ret_val = e1000_disable_phy_wakeup_reg_access_bm(hw, &phy_reg);
-out:
return ret_val;
}
@@ -3459,10 +3494,16 @@ out:
void e1000_power_up_phy_copper(struct e1000_hw *hw)
{
u16 mii_reg = 0;
+ u16 power_reg = 0;
/* The PHY will retain its settings across a power down/up cycle */
hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
mii_reg &= ~MII_CR_POWER_DOWN;
+ if (hw->phy.type == e1000_phy_i210) {
+ hw->phy.ops.read_reg(hw, GS40G_COPPER_SPEC, &power_reg);
+ power_reg &= ~GS40G_CS_POWER_DOWN;
+ hw->phy.ops.write_reg(hw, GS40G_COPPER_SPEC, power_reg);
+ }
hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
}
@@ -3477,10 +3518,17 @@ void e1000_power_up_phy_copper(struct e1000_hw *hw)
void e1000_power_down_phy_copper(struct e1000_hw *hw)
{
u16 mii_reg = 0;
+ u16 power_reg = 0;
/* The PHY will retain its settings across a power down/up cycle */
hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
mii_reg |= MII_CR_POWER_DOWN;
+ /* i210 Phy requires an additional bit for power up/down */
+ if (hw->phy.type == e1000_phy_i210) {
+ hw->phy.ops.read_reg(hw, GS40G_COPPER_SPEC, &power_reg);
+ power_reg |= GS40G_CS_POWER_DOWN;
+ hw->phy.ops.write_reg(hw, GS40G_COPPER_SPEC, power_reg);
+ }
hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
msec_delay(1);
}
@@ -3646,7 +3694,7 @@ static s32 __e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data,
if ((hw->phy.type == e1000_phy_82578) &&
(hw->phy.revision >= 1) &&
(hw->phy.addr == 2) &&
- ((MAX_PHY_REG_ADDRESS & reg) == 0) &&
+ !(MAX_PHY_REG_ADDRESS & reg) &&
(data & (1 << 11))) {
u16 data2 = 0x7EFF;
ret_val = e1000_access_phy_debug_regs_hv(hw,
@@ -3770,7 +3818,7 @@ static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
ret_val = e1000_write_phy_reg_mdic(hw, addr_reg, (u16)offset & 0x3F);
if (ret_val) {
DEBUGOUT("Could not write the Address Offset port register\n");
- goto out;
+ return ret_val;
}
/* Read or write the data value next */
@@ -3779,12 +3827,9 @@ static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
else
ret_val = e1000_write_phy_reg_mdic(hw, data_reg, *data);
- if (ret_val) {
+ if (ret_val)
DEBUGOUT("Could not access the Data port register\n");
- goto out;
- }
-out:
return ret_val;
}
@@ -3807,24 +3852,24 @@ s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw)
DEBUGFUNC("e1000_link_stall_workaround_hv");
if (hw->phy.type != e1000_phy_82578)
- goto out;
+ return E1000_SUCCESS;
/* Do not apply workaround if in PHY loopback bit 14 set */
hw->phy.ops.read_reg(hw, PHY_CONTROL, &data);
if (data & PHY_CONTROL_LB)
- goto out;
+ return E1000_SUCCESS;
/* check if link is up and at 1Gbps */
ret_val = hw->phy.ops.read_reg(hw, BM_CS_STATUS, &data);
if (ret_val)
- goto out;
+ return ret_val;
data &= BM_CS_STATUS_LINK_UP | BM_CS_STATUS_RESOLVED |
BM_CS_STATUS_SPEED_MASK;
if (data != (BM_CS_STATUS_LINK_UP | BM_CS_STATUS_RESOLVED |
BM_CS_STATUS_SPEED_1000))
- goto out;
+ return E1000_SUCCESS;
msec_delay(200);
@@ -3833,13 +3878,10 @@ s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw)
HV_MUX_DATA_CTRL_GEN_TO_MAC |
HV_MUX_DATA_CTRL_FORCE_SPEED);
if (ret_val)
- goto out;
-
- ret_val = hw->phy.ops.write_reg(hw, HV_MUX_DATA_CTRL,
- HV_MUX_DATA_CTRL_GEN_TO_MAC);
+ return ret_val;
-out:
- return ret_val;
+ return hw->phy.ops.write_reg(hw, HV_MUX_DATA_CTRL,
+ HV_MUX_DATA_CTRL_GEN_TO_MAC);
}
/**
@@ -3885,13 +3927,13 @@ s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw)
ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
if (ret_val)
- goto out;
+ return ret_val;
e1000_phy_force_speed_duplex_setup(hw, &phy_data);
ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
if (ret_val)
- goto out;
+ return ret_val;
usec_delay(1);
@@ -3901,7 +3943,7 @@ s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw)
ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
100000, &link);
if (ret_val)
- goto out;
+ return ret_val;
if (!link)
DEBUGOUT("Link taking longer than expected.\n");
@@ -3909,11 +3951,8 @@ s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw)
/* Try once more */
ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
100000, &link);
- if (ret_val)
- goto out;
}
-out:
return ret_val;
}
@@ -3937,35 +3976,34 @@ s32 e1000_get_phy_info_82577(struct e1000_hw *hw)
ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
if (ret_val)
- goto out;
+ return ret_val;
if (!link) {
DEBUGOUT("Phy info is only valid if link is up\n");
- ret_val = -E1000_ERR_CONFIG;
- goto out;
+ return -E1000_ERR_CONFIG;
}
phy->polarity_correction = TRUE;
ret_val = e1000_check_polarity_82577(hw);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = phy->ops.read_reg(hw, I82577_PHY_STATUS_2, &data);
if (ret_val)
- goto out;
+ return ret_val;
- phy->is_mdix = (data & I82577_PHY_STATUS2_MDIX) ? TRUE : FALSE;
+ phy->is_mdix = !!(data & I82577_PHY_STATUS2_MDIX);
if ((data & I82577_PHY_STATUS2_SPEED_MASK) ==
I82577_PHY_STATUS2_SPEED_1000MBPS) {
ret_val = hw->phy.ops.get_cable_length(hw);
if (ret_val)
- goto out;
+ return ret_val;
ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data);
if (ret_val)
- goto out;
+ return ret_val;
phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
? e1000_1000t_rx_status_ok
@@ -3980,8 +4018,7 @@ s32 e1000_get_phy_info_82577(struct e1000_hw *hw)
phy->remote_rx = e1000_1000t_rx_status_undefined;
}
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -4001,7 +4038,7 @@ s32 e1000_get_cable_length_82577(struct e1000_hw *hw)
ret_val = phy->ops.read_reg(hw, I82577_PHY_DIAG_STATUS, &phy_data);
if (ret_val)
- goto out;
+ return ret_val;
length = (phy_data & I82577_DSTATUS_CABLE_LENGTH) >>
I82577_DSTATUS_CABLE_LENGTH_SHIFT;
@@ -4011,6 +4048,68 @@ s32 e1000_get_cable_length_82577(struct e1000_hw *hw)
phy->cable_length = length;
-out:
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_write_phy_reg_gs40g - Write GS40G 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 e1000_write_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 data)
+{
+ s32 ret_val;
+ u16 page = offset >> GS40G_PAGE_SHIFT;
+
+ DEBUGFUNC("e1000_write_phy_reg_gs40g");
+
+ offset = offset & GS40G_OFFSET_MASK;
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_write_phy_reg_mdic(hw, GS40G_PAGE_SELECT, page);
+ if (ret_val)
+ goto release;
+ ret_val = e1000_write_phy_reg_mdic(hw, offset, data);
+
+release:
+ hw->phy.ops.release(hw);
+ return ret_val;
+}
+
+/**
+ * e1000_read_phy_reg_gs40g - Read GS40G PHY register
+ * @hw: pointer to the HW structure
+ * @offset: lower half is register offset to read to
+ * upper half is page to use.
+ * @data: data to read at register offset
+ *
+ * Acquires semaphore, if necessary, then reads the data in the PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ **/
+s32 e1000_read_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+ s32 ret_val;
+ u16 page = offset >> GS40G_PAGE_SHIFT;
+
+ DEBUGFUNC("e1000_read_phy_reg_gs40g");
+
+ offset = offset & GS40G_OFFSET_MASK;
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_write_phy_reg_mdic(hw, GS40G_PAGE_SELECT, page);
+ if (ret_val)
+ goto release;
+ ret_val = e1000_read_phy_reg_mdic(hw, offset, data);
+
+release:
+ hw->phy.ops.release(hw);
return ret_val;
}
diff --git a/sys/dev/e1000/e1000_phy.h b/sys/dev/e1000/e1000_phy.h
index 93d0afc..edcbcab 100644
--- a/sys/dev/e1000/e1000_phy.h
+++ b/sys/dev/e1000/e1000_phy.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2011, Intel Corporation
+ Copyright (c) 2001-2012, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -41,6 +41,10 @@ void e1000_null_phy_generic(struct e1000_hw *hw);
s32 e1000_null_lplu_state(struct e1000_hw *hw, bool active);
s32 e1000_null_write_reg(struct e1000_hw *hw, u32 offset, u16 data);
s32 e1000_null_set_page(struct e1000_hw *hw, u16 data);
+s32 e1000_read_i2c_byte_null(struct e1000_hw *hw, u8 byte_offset,
+ u8 dev_addr, u8 *data);
+s32 e1000_write_i2c_byte_null(struct e1000_hw *hw, u8 byte_offset,
+ u8 dev_addr, u8 data);
s32 e1000_check_downshift_generic(struct e1000_hw *hw);
s32 e1000_check_polarity_m88(struct e1000_hw *hw);
s32 e1000_check_polarity_igp(struct e1000_hw *hw);
@@ -112,6 +116,8 @@ s32 e1000_check_polarity_82577(struct e1000_hw *hw);
s32 e1000_get_phy_info_82577(struct e1000_hw *hw);
s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw);
s32 e1000_get_cable_length_82577(struct e1000_hw *hw);
+s32 e1000_write_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000_read_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 *data);
#define E1000_MAX_PHY_ADDR 8
@@ -128,6 +134,17 @@ s32 e1000_get_cable_length_82577(struct e1000_hw *hw);
#define IGP_PAGE_SHIFT 5
#define PHY_REG_MASK 0x1F
+/* GS40G - I210 PHY defines */
+#define GS40G_PAGE_SELECT 0x16
+#define GS40G_PAGE_SHIFT 16
+#define GS40G_OFFSET_MASK 0xFFFF
+#define GS40G_PAGE_2 0x20000
+#define GS40G_MAC_REG2 0x15
+#define GS40G_MAC_LB 0x4140
+#define GS40G_MAC_SPEED_1G 0X0006
+#define GS40G_COPPER_SPEC 0x0010
+#define GS40G_CS_POWER_DOWN 0x0002
+
/* BM/HV Specific Registers */
#define BM_PORT_CTRL_PAGE 769
#define BM_PCIE_PAGE 770
@@ -174,8 +191,9 @@ s32 e1000_get_cable_length_82577(struct e1000_hw *hw);
#define I82577_PHY_STATUS2_SPEED_100MBPS 0x0100
/* I82577 PHY Control 2 */
-#define I82577_PHY_CTRL2_AUTO_MDIX 0x0400
-#define I82577_PHY_CTRL2_FORCE_MDI_MDIX 0x0200
+#define I82577_PHY_CTRL2_MANUAL_MDIX 0x0200
+#define I82577_PHY_CTRL2_AUTO_MDI_MDIX 0x0400
+#define I82577_PHY_CTRL2_MDIX_CFG_MASK 0x0600
/* I82577 PHY Diagnostics Status */
#define I82577_DSTATUS_CABLE_LENGTH 0x03FC
diff --git a/sys/dev/e1000/e1000_regs.h b/sys/dev/e1000/e1000_regs.h
index 2cc89d5..8c4e4af 100644
--- a/sys/dev/e1000/e1000_regs.h
+++ b/sys/dev/e1000/e1000_regs.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2011, Intel Corporation
+ Copyright (c) 2001-2012, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -51,6 +51,7 @@
#define E1000_BARCTRL_FLSIZE 0x0700 /* BAR ctrl Flsize */
#define E1000_BARCTRL_CSRSIZE 0x2000 /* BAR ctrl CSR size */
#define E1000_I350_BARCTRL 0x5BFC /* BAR ctrl reg */
+#define E1000_I350_DTXMXPKTSZ 0x355C /* Maximum sent packet size reg*/
#define E1000_SCTL 0x00024 /* SerDes Control - RW */
#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */
#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */
@@ -143,6 +144,62 @@
#define E1000_PBRWAC 0x024E8 /* Rx packet buffer wrap around counter - RO */
#define E1000_RDTR 0x02820 /* Rx Delay Timer - RW */
#define E1000_RADV 0x0282C /* Rx Interrupt Absolute Delay Timer - RW */
+#define E1000_SRWR 0x12018 /* Shadow Ram Write Register - RW */
+#define E1000_I210_FLMNGCTL 0x12038
+#define E1000_I210_FLMNGDATA 0x1203C
+#define E1000_I210_FLMNGCNT 0x12040
+
+#define E1000_I210_FLSWCTL 0x12048
+#define E1000_I210_FLSWDATA 0x1204C
+#define E1000_I210_FLSWCNT 0x12050
+
+#define E1000_I210_FLA 0x1201C
+
+#define E1000_INVM_DATA_REG(_n) (0x12120 + 4*(_n))
+#define E1000_INVM_SIZE 64 /* Number of INVM Data Registers */
+
+/* QAV Tx mode control register */
+#define E1000_I210_TQAVCTRL 0x3570
+
+/* QAV Tx mode control register bitfields masks */
+/* QAV enable */
+#define E1000_TQAVCTRL_MODE (1 << 0)
+/* Fetching arbitration type */
+#define E1000_TQAVCTRL_FETCH_ARB (1 << 4)
+/* Fetching timer enable */
+#define E1000_TQAVCTRL_FETCH_TIMER_ENABLE (1 << 5)
+/* Launch arbitration type */
+#define E1000_TQAVCTRL_LAUNCH_ARB (1 << 8)
+/* Launch timer enable */
+#define E1000_TQAVCTRL_LAUNCH_TIMER_ENABLE (1 << 9)
+/* SP waits for SR enable */
+#define E1000_TQAVCTRL_SP_WAIT_SR (1 << 10)
+/* Fetching timer correction */
+#define E1000_TQAVCTRL_FETCH_TIMER_DELTA_OFFSET 16
+#define E1000_TQAVCTRL_FETCH_TIMER_DELTA \
+ (0xFFFF << E1000_TQAVCTRL_FETCH_TIMER_DELTA_OFFSET)
+
+/* High credit registers where _n can be 0 or 1. */
+#define E1000_I210_TQAVHC(_n) (0x300C + 0x40 * (_n))
+
+/* Queues fetch arbitration priority control register */
+#define E1000_I210_TQAVARBCTRL 0x3574
+/* Queues priority masks where _n and _p can be 0-3. */
+#define E1000_TQAVARBCTRL_QUEUE_PRI(_n, _p) ((_p) << (2 * _n))
+/* QAV Tx mode control registers where _n can be 0 or 1. */
+#define E1000_I210_TQAVCC(_n) (0x3004 + 0x40 * (_n))
+
+/* QAV Tx mode control register bitfields masks */
+#define E1000_TQAVCC_IDLE_SLOPE 0xFFFF /* Idle slope */
+#define E1000_TQAVCC_KEEP_CREDITS (1 << 30) /* Keep credits opt enable */
+#define E1000_TQAVCC_QUEUE_MODE (1 << 31) /* SP vs. SR Tx mode */
+
+/* Good transmitted packets counter registers */
+#define E1000_PQGPTC(_n) (0x010014 + (0x100 * (_n)))
+
+/* Queues packet buffer size masks where _n can be 0-3 and _s 0-63 [kB] */
+#define E1000_I210_TXPBS_SIZE(_n, _s) ((_s) << (6 * _n))
+
/*
* Convenience macros
*
@@ -424,10 +481,11 @@
#define E1000_HOST_IF 0x08800 /* Host Interface */
#define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */
#define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */
+#define E1000_HIBBA 0x8F40 /* Host Interface Buffer Base Address */
/* Flexible Host Filter Table */
-#define E1000_FHFT(_n) (0x09000 + (_n * 0x100))
+#define E1000_FHFT(_n) (0x09000 + ((_n) * 0x100))
/* Ext Flexible Host Filter Table */
-#define E1000_FHFT_EXT(_n) (0x09A00 + (_n * 0x100))
+#define E1000_FHFT_EXT(_n) (0x09A00 + ((_n) * 0x100))
#define E1000_KMRNCTRLSTA 0x00034 /* MAC-PHY interface - RW */
@@ -590,10 +648,6 @@
/* PCIe Parity Status Register */
#define E1000_PCIEERRSTS 0x05BA8
-#define E1000_LTRMINV 0x5BB0 /* LTR Minimum Value */
-#define E1000_LTRMAXV 0x5BB4 /* LTR Maximum Value */
-#define E1000_DOBFFCTL 0x3F24 /* DMA OBFF Control Register */
-
#define E1000_PROXYS 0x5F64 /* Proxying Status */
#define E1000_PROXYFC 0x5F60 /* Proxying Filter Control */
/* Thermal sensor configuration and status registers */
@@ -603,7 +657,7 @@
#define E1000_THHIGHTC 0x0810C /* High Threshold Control */
#define E1000_THSTAT 0x08110 /* Thermal Sensor Status */
-/*Energy Efficient Ethernet "EEE" registers */
+/* Energy Efficient Ethernet "EEE" registers */
#define E1000_IPCNFG 0x0E38 /* Internal PHY Configuration */
#define E1000_LTRC 0x01A0 /* Latency Tolerance Reporting Control */
#define E1000_EEER 0x0E30 /* Energy Efficient Ethernet "EEE"*/
@@ -617,4 +671,9 @@
#define E1000_O2BGPTC 0x08FE4 /* OS2BMC packets received by BMC */
#define E1000_O2BSPC 0x0415C /* OS2BMC packets transmitted by host */
+#define E1000_LTRMINV 0x5BB0 /* LTR Minimum Value */
+#define E1000_LTRMAXV 0x5BB4 /* LTR Maximum Value */
+#define E1000_DOBFFCTL 0x3F24 /* DMA OBFF Control Register */
+
+
#endif
diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c
index 95306cd..15c0cbf 100644
--- a/sys/dev/e1000/if_em.c
+++ b/sys/dev/e1000/if_em.c
@@ -638,7 +638,7 @@ em_attach(device_t dev)
/* Sysctl for setting Energy Efficient Ethernet */
em_set_sysctl_value(adapter, "eee_control",
"enable Energy Efficient Ethernet",
- &hw->dev_spec.ich8lan.eee_disable, eee_setting);
+ (int *)&hw->dev_spec.ich8lan.eee_disable, eee_setting);
/*
** Start from a known state, this is
diff --git a/sys/dev/e1000/if_igb.c b/sys/dev/e1000/if_igb.c
index cb6c63f..0db4a49 100644
--- a/sys/dev/e1000/if_igb.c
+++ b/sys/dev/e1000/if_igb.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2011, Intel Corporation
+ Copyright (c) 2001-2012, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -100,7 +100,7 @@ int igb_display_debug_stats = 0;
/*********************************************************************
* Driver version:
*********************************************************************/
-char igb_driver_version[] = "version - 2.3.1";
+char igb_driver_version[] = "version - 2.3.4";
/*********************************************************************
@@ -150,6 +150,14 @@ static igb_vendor_info_t igb_vendor_info_array[] =
{ 0x8086, E1000_DEV_ID_I350_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_I350_SGMII, PCI_ANY_ID, PCI_ANY_ID, 0},
{ 0x8086, E1000_DEV_ID_I350_VF, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_I210_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_I210_COPPER_IT, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_I210_COPPER_OEM1,
+ PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_I210_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_I210_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_I210_SGMII, PCI_ANY_ID, PCI_ANY_ID, 0},
+ { 0x8086, E1000_DEV_ID_I211_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0},
/* required last entry */
{ 0, 0, 0, 0, 0}
};
@@ -580,9 +588,10 @@ igb_attach(device_t dev)
adapter, 0, igb_sysctl_dmac, "I", "DMA Coalesce");
igb_set_sysctl_value(adapter, "eee_disabled",
"enable Energy Efficient Ethernet",
- &adapter->hw.dev_spec._82575.eee_disable,
+ (int *)&adapter->hw.dev_spec._82575.eee_disable,
TRUE);
- e1000_set_eee_i350(&adapter->hw);
+ if (adapter->hw.phy.media_type == e1000_media_type_copper)
+ e1000_set_eee_i350(&adapter->hw);
}
/*
@@ -593,7 +602,9 @@ igb_attach(device_t dev)
e1000_reset_hw(&adapter->hw);
/* Make sure we have a good EEPROM before we read from it */
- if (e1000_validate_nvm_checksum(&adapter->hw) < 0) {
+ if (((adapter->hw.mac.type != e1000_i210) &&
+ (adapter->hw.mac.type != e1000_i211)) &&
+ (e1000_validate_nvm_checksum(&adapter->hw) < 0)) {
/*
** Some PCI-E parts fail the first check due to
** the link being in sleep state, call it again,
@@ -756,6 +767,8 @@ igb_detach(device_t dev)
if (adapter->vlan_detach != NULL)
EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach);
+ ether_ifdetach(adapter->ifp);
+
callout_drain(&adapter->timer);
#ifdef DEV_NETMAP
@@ -924,7 +937,8 @@ igb_start(struct ifnet *ifp)
return;
}
-#else
+#else /* __FreeBSD_version >= 800000 */
+
/*
** Multiqueue Transmit driver
**
@@ -936,13 +950,11 @@ igb_mq_start(struct ifnet *ifp, struct mbuf *m)
struct igb_queue *que;
struct tx_ring *txr;
int i, err = 0;
- bool moveable = TRUE;
/* Which queue to use */
- if ((m->m_flags & M_FLOWID) != 0) {
+ if ((m->m_flags & M_FLOWID) != 0)
i = m->m_pkthdr.flowid % adapter->num_queues;
- moveable = FALSE;
- } else
+ else
i = curcpu % adapter->num_queues;
txr = &adapter->tx_rings[i];
@@ -953,7 +965,7 @@ igb_mq_start(struct ifnet *ifp, struct mbuf *m)
IGB_TX_UNLOCK(txr);
} else {
err = drbr_enqueue(ifp, txr->br, m);
- taskqueue_enqueue(que->tq, &txr->txq_task);
+ taskqueue_enqueue(que->tq, &que->que_task);
}
return (err);
@@ -1342,8 +1354,8 @@ igb_init_locked(struct adapter *adapter)
}
/* Set Energy Efficient Ethernet */
-
- e1000_set_eee_i350(&adapter->hw);
+ if (adapter->hw.phy.media_type == e1000_media_type_copper)
+ e1000_set_eee_i350(&adapter->hw);
}
static void
@@ -2566,6 +2578,8 @@ igb_configure_queues(struct adapter *adapter)
switch (adapter->hw.mac.type) {
case e1000_82580:
case e1000_i350:
+ case e1000_i210:
+ case e1000_i211:
case e1000_vfadapt:
case e1000_vfadapt_i350:
/* RX entries */
@@ -2764,7 +2778,7 @@ static int
igb_setup_msix(struct adapter *adapter)
{
device_t dev = adapter->dev;
- int rid, want, queues, msgs;
+ int rid, want, queues, msgs, maxqueues;
/* tuneable override */
if (igb_enable_msix == 0)
@@ -2795,16 +2809,29 @@ igb_setup_msix(struct adapter *adapter)
/* Manual override */
if (igb_num_queues != 0)
queues = igb_num_queues;
- if (queues > 8) /* max queues */
- queues = 8;
-
- /* Can have max of 4 queues on 82575 */
- if ((adapter->hw.mac.type == e1000_82575) && (queues > 4))
- queues = 4;
- /* Limit the VF devices to one queue */
- if (adapter->vf_ifp)
- queues = 1;
+ /* Sanity check based on HW */
+ switch (adapter->hw.mac.type) {
+ case e1000_82575:
+ maxqueues = 4;
+ break;
+ case e1000_82576:
+ case e1000_82580:
+ case e1000_i350:
+ maxqueues = 8;
+ break;
+ case e1000_i210:
+ maxqueues = 4;
+ break;
+ case e1000_i211:
+ maxqueues = 2;
+ break;
+ default: /* VF interfaces */
+ maxqueues = 1;
+ break;
+ }
+ if (queues > maxqueues)
+ queues = maxqueues;
/*
** One vector (RX/TX pair) per queue
@@ -2875,6 +2902,9 @@ igb_reset(struct adapter *adapter)
pba = E1000_READ_REG(hw, E1000_RXPBS);
pba = e1000_rxpbs_adjust_82580(pba);
break;
+ case e1000_i210:
+ case e1000_i211:
+ pba = E1000_PBA_34K;
default:
break;
}
@@ -2942,7 +2972,9 @@ igb_reset(struct adapter *adapter)
device_printf(dev, "Hardware Initialization Failed\n");
/* Setup DMA Coalescing */
- if (hw->mac.type == e1000_i350) {
+ if ((hw->mac.type > e1000_82580) &&
+ (hw->mac.type != e1000_i211)) {
+ u32 dmac;
u32 reg = ~E1000_DMACR_DMAC_EN;
if (adapter->dmac == 0) { /* Disabling it */
@@ -2950,26 +2982,36 @@ igb_reset(struct adapter *adapter)
goto reset_out;
}
- hwm = (pba - 4) << 10;
- reg = (((pba-6) << E1000_DMACR_DMACTHR_SHIFT)
- & E1000_DMACR_DMACTHR_MASK);
+ /* Set starting thresholds */
+ E1000_WRITE_REG(hw, E1000_DMCTXTH, 0);
+ E1000_WRITE_REG(hw, E1000_DMCRTRH, 0);
+ hwm = 64 * pba - adapter->max_frame_size / 16;
+ if (hwm < 64 * (pba - 6))
+ hwm = 64 * (pba - 6);
+ reg = E1000_READ_REG(hw, E1000_FCRTC);
+ reg &= ~E1000_FCRTC_RTH_COAL_MASK;
+ reg |= ((hwm << E1000_FCRTC_RTH_COAL_SHIFT)
+ & E1000_FCRTC_RTH_COAL_MASK);
+ E1000_WRITE_REG(hw, E1000_FCRTC, reg);
+
+
+ dmac = pba - adapter->max_frame_size / 512;
+ if (dmac < pba - 10)
+ dmac = pba - 10;
+ reg = E1000_READ_REG(hw, E1000_DMACR);
+ reg &= ~E1000_DMACR_DMACTHR_MASK;
+ reg = ((dmac << E1000_DMACR_DMACTHR_SHIFT)
+ & E1000_DMACR_DMACTHR_MASK);
/* transition to L0x or L1 if available..*/
reg |= (E1000_DMACR_DMAC_EN | E1000_DMACR_DMAC_LX_MASK);
-
/* timer = value in adapter->dmac in 32usec intervals */
reg |= (adapter->dmac >> 5);
E1000_WRITE_REG(hw, E1000_DMACR, reg);
- /* No lower threshold */
- E1000_WRITE_REG(hw, E1000_DMCRTRH, 0);
-
- /* set hwm to PBA - 2 * max frame size */
- E1000_WRITE_REG(hw, E1000_FCRTC, hwm);
-
/* Set the interval before transition */
reg = E1000_READ_REG(hw, E1000_DMCTLX);
- reg |= 0x800000FF; /* 255 usec */
+ reg |= 0x80000004;
E1000_WRITE_REG(hw, E1000_DMCTLX, reg);
/* free space in tx packet buffer to wake from DMA coal */
@@ -2978,9 +3020,15 @@ igb_reset(struct adapter *adapter)
/* make low power state decision controlled by DMA coal */
reg = E1000_READ_REG(hw, E1000_PCIEMISC);
- E1000_WRITE_REG(hw, E1000_PCIEMISC,
- reg | E1000_PCIEMISC_LX_DECISION);
+ reg &= ~E1000_PCIEMISC_LX_DECISION;
+ E1000_WRITE_REG(hw, E1000_PCIEMISC, reg);
device_printf(dev, "DMA Coalescing enabled\n");
+
+ } else if (hw->mac.type == e1000_82580) {
+ u32 reg = E1000_READ_REG(hw, E1000_PCIEMISC);
+ E1000_WRITE_REG(hw, E1000_DMACR, 0);
+ E1000_WRITE_REG(hw, E1000_PCIEMISC,
+ reg & ~E1000_PCIEMISC_LX_DECISION);
}
reset_out:
diff --git a/sys/modules/igb/Makefile b/sys/modules/igb/Makefile
index a66c32a..45b7ec2 100644
--- a/sys/modules/igb/Makefile
+++ b/sys/modules/igb/Makefile
@@ -6,7 +6,7 @@ SRCS += if_igb.c $(SHARED_SRCS)
SHARED_SRCS = e1000_api.c e1000_phy.c e1000_nvm.c e1000_mac.c e1000_manage.c
SHARED_SRCS += e1000_80003es2lan.c e1000_82542.c e1000_82541.c e1000_82543.c
SHARED_SRCS += e1000_82540.c e1000_ich8lan.c e1000_82571.c e1000_osdep.c
-SHARED_SRCS += e1000_82575.c e1000_vf.c e1000_mbx.c
+SHARED_SRCS += e1000_82575.c e1000_vf.c e1000_mbx.c e1000_i210.c
CFLAGS += -I${.CURDIR}/../../dev/e1000 -DSMP
OpenPOWER on IntegriCloud