summaryrefslogtreecommitdiffstats
path: root/sys/dev/e1000/e1000_mac.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/e1000/e1000_mac.c')
-rw-r--r--sys/dev/e1000/e1000_mac.c598
1 files changed, 275 insertions, 323 deletions
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;
}
OpenPOWER on IntegriCloud