e1000_82541.c revision bd9f6899328e19cbb74e3ad02f5c32002285887e
/*
* This file is provided under a CDDLv1 license. When using or
* redistributing this file, you may do so under this license.
* In redistributing this file this license must be included
* and no other modification of this header file is permitted.
*
* CDDL LICENSE SUMMARY
*
* Copyright(c) 1999 - 2009 Intel Corporation. All rights reserved.
*
* The contents of this file are subject to the terms of Version
* 1.0 of the Common Development and Distribution License (the "License").
*
* You should have received a copy of the License with this software.
* You can obtain a copy of the License at
* See the License for the specific language governing permissions
* and limitations under the License.
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms of the CDDLv1.
*/
/*
* IntelVersion: 1.68 v3-1-10-1_2009-9-18_Release14-6
*/
/*
* 82541EI Gigabit Ethernet Controller
* 82541ER Gigabit Ethernet Controller
* 82541GI Gigabit Ethernet Controller
* 82541PI Gigabit Ethernet Controller
* 82547EI Gigabit Ethernet Controller
* 82547GI Gigabit Ethernet Controller
*/
#include "e1000_api.h"
bool active);
bool link_up);
static const u16 e1000_igp_cable_length_table[] =
{5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 10, 10, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20, 25, 25, 25,
25, 25, 25, 25, 30, 30, 30, 30, 40, 40, 40, 40, 40, 40, 40, 40,
40, 50, 50, 50, 50, 50, 50, 50, 60, 60, 60, 60, 60, 60, 60, 60,
60, 70, 70, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 90, 90, 90,
90, 90, 90, 90, 90, 90, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
100, 100, 100, 100, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
110, 110, 110, 110, 110, 110, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120};
#define IGP01E1000_AGC_LENGTH_TABLE_SIZE \
(sizeof (e1000_igp_cable_length_table) / \
sizeof (e1000_igp_cable_length_table[0]))
/*
* e1000_init_phy_params_82541 - Init PHY func ptrs.
* @hw: pointer to the HW structure
*/
static s32
{
DEBUGFUNC("e1000_init_phy_params_82541");
/* Function Pointers */
if (ret_val)
goto out;
/* Verify phy id */
ret_val = -E1000_ERR_PHY;
goto out;
}
out:
return (ret_val);
}
/*
* e1000_init_nvm_params_82541 - Init NVM func ptrs.
* @hw: pointer to the HW structure
*/
static s32
{
DEBUGFUNC("e1000_init_nvm_params_82541");
break;
eecd &= ~E1000_EECD_ADDR_BITS;
break;
eecd |= E1000_EECD_SIZE;
break;
eecd &= ~E1000_EECD_SIZE;
break;
default:
break;
}
? 16 : 8;
? 32 : 8;
/* Function Pointers */
/*
* nvm->word_size must be discovered after the pointers
* are set so we can verify the size from the nvm image
* itself. Temporarily set it to a dummy value so the
* read will work.
*/
if (ret_val)
goto out;
/*
* if size != 0, it can be added to a constant and become
* the left-shift value to set the word_size. Otherwise,
* word_size stays at 64.
*/
if (size) {
}
} else {
? 8 : 6;
? 256 : 64;
/* Function Pointers */
}
out:
return (ret_val);
}
/*
* e1000_init_mac_params_82541 - Init MAC func ptrs.
* @hw: pointer to the HW structure
*/
static s32
{
DEBUGFUNC("e1000_init_mac_params_82541");
/* Set media type */
/* Set mta register count */
/* Set rar entry count */
/* Set if part includes ASF firmware */
mac->asf_firmware_present = true;
/* Function Pointers */
/* function id */
/* reset */
/* hw initialization */
/* link setup */
/* physical interface link setup */
/* check for link */
/* link info */
/* multicast address update */
/* writing VFTA */
/* clearing VFTA */
/* setting MTA */
/* ID LED init */
/* setup LED */
/* cleanup LED */
/* clear hardware counters */
return (E1000_SUCCESS);
}
/*
* e1000_init_function_pointers_82541 - Init func ptrs.
* @hw: pointer to the HW structure
*
* Called to initialize all function pointers and parameters.
*/
void
{
DEBUGFUNC("e1000_init_function_pointers_82541");
}
/*
* e1000_reset_hw_82541 - Reset hardware
* @hw: pointer to the HW structure
*
* This resets the hardware into a known state.
*/
static s32
{
DEBUGFUNC("e1000_reset_hw_82541");
DEBUGOUT("Masking off all interrupts\n");
dev_spec->tx_fifo_head = 0;
/*
* Delay to allow any outstanding PCI transactions to complete
* before resetting the device.
*/
msec_delay(10);
/* Must reset the Phy before resetting the MAC */
msec_delay(5);
}
DEBUGOUT("Issuing a global reset to 82541/82547 MAC\n");
case e1000_82541:
case e1000_82541_rev_2:
/*
* These controllers can't ack the 64-bit write when
* issuing the reset, so we use IO-mapping as a
* workaround to issue the reset.
*/
break;
default:
break;
}
/* Wait for NVM reload */
msec_delay(20);
/* Disable HW ARPs on ASF enabled adapters */
manc &= ~E1000_MANC_ARP_EN;
(void) e1000_phy_init_script_82541(hw);
/* Configure activity LED after Phy reset */
}
/* Once again, mask the interrupts */
DEBUGOUT("Masking off all interrupts\n");
/* Clear any pending interrupt events. */
return (E1000_SUCCESS);
}
/*
* e1000_init_hw_82541 - Initialize hardware
* @hw: pointer to the HW structure
*
* This inits the hardware readying it for operation.
*/
static s32
{
DEBUGFUNC("e1000_init_hw_82541");
/* Initialize identification LED */
if (ret_val) {
DEBUGOUT("Error initializing identification LED\n");
/* This is not fatal and we should not stop init due to this */
}
/* Storing the Speed Power Down value for later use */
&dev_spec->spd_default);
if (ret_val)
goto out;
/* Disabling VLAN filtering */
DEBUGOUT("Initializing the IEEE VLAN\n");
/* Setup the receive address. */
/* Zero out the Multicast HASH table */
DEBUGOUT("Zeroing the MTA\n");
for (i = 0; i < mac->mta_reg_count; i++) {
/*
* Avoid back to back register writes by adding the register
* read (flush). This is to protect against some strange
* bridge configurations that may issue Memory Write Block
* (MWB) to our register space.
*/
}
/* Setup link and flow control */
/*
* Clear all of the statistics registers (clear on read). It is
* important that we do this after we have tried to establish link
* because the symbol error count will increment wildly if there
* is no link.
*/
out:
return (ret_val);
}
/*
* e1000_get_link_up_info_82541 - Report speed and duplex
* @hw: pointer to the HW structure
* @speed: pointer to speed buffer
* @duplex: pointer to duplex buffer
*
* Retrieve the current speed and duplex configuration.
*/
static s32
{
DEBUGFUNC("e1000_get_link_up_info_82541");
if (ret_val)
goto out;
if (!phy->speed_downgraded)
goto out;
/*
* IGP01 PHY may advertise full duplex operation after speed
* downgrade even if it is operating at half duplex.
* Here we set the duplex settings to match the duplex in the
* link partner's capabilities.
*/
if (ret_val)
goto out;
if (!(data & NWAY_ER_LP_NWAY_CAPS)) {
*duplex = HALF_DUPLEX;
} else {
if (ret_val)
goto out;
if (!(data & NWAY_LPAR_100TX_FD_CAPS))
*duplex = HALF_DUPLEX;
if (!(data & NWAY_LPAR_10T_FD_CAPS))
*duplex = HALF_DUPLEX;
}
}
out:
return (ret_val);
}
/*
* e1000_phy_hw_reset_82541 - PHY hardware reset
* @hw: pointer to the HW structure
*
* Verify the reset block is not blocking us from resetting. Acquire
* bit in the PHY. Wait the appropriate delay time for the device to
* reset and release the semaphore (if necessary).
*/
static s32
{
DEBUGFUNC("e1000_phy_hw_reset_82541");
if (ret_val)
goto out;
(void) e1000_phy_init_script_82541(hw);
/* Configure activity LED after PHY reset */
}
out:
return (ret_val);
}
/*
* e1000_setup_copper_link_82541 - Configure copper link settings
* @hw: pointer to the HW structure
*
* Calls the appropriate function to configure the link for auto-neg or forced
* speed and duplex. Then we check for link, once link is established calls
* to configure collision distance and flow control are called. If link is
* not established, we return -E1000_ERR_PHY (-2).
*/
static s32
{
DEBUGFUNC("e1000_setup_copper_link_82541");
ctrl |= E1000_CTRL_SLU;
/* Earlier revs of the IGP phy require us to force MDI. */
} else {
}
if (ret_val)
goto out;
}
/* Configure activity LED after Phy reset */
out:
return (ret_val);
}
/*
* @hw: pointer to the HW structure
*
* This checks the link condition of the adapter and stores the
* results in the hw->mac structure.
*/
static s32
{
bool link;
DEBUGFUNC("e1000_check_for_link_82541");
/*
* We only want to go out to the PHY registers to see if Auto-Neg
* get_link_status flag is set upon receiving a Link Status
* Change or Rx Sequence Error interrupt.
*/
if (!mac->get_link_status) {
goto out;
}
/*
* First we want to see if the MII Status Register reports
* of the PHY.
*/
if (ret_val)
goto out;
if (!link) {
goto out; /* No link detected */
}
mac->get_link_status = false;
/*
* Check if there was DownShift, must be checked
* immediately after link-up
*/
(void) e1000_check_downshift_generic(hw);
/*
* we have already determined whether we have link or not.
*/
goto out;
}
/*
* Auto-Neg is enabled. Auto Speed Detection takes care
* configure Collision Distance in the MAC.
*/
/*
* Configure Flow Control now that Auto-Neg has completed.
* First, we need to restore the desired flow control
* settings because we may have had to re-autoneg with a
* different link partner.
*/
if (ret_val) {
DEBUGOUT("Error configuring flow control\n");
}
out:
return (ret_val);
}
/*
* e1000_config_dsp_after_link_change_82541 - Config DSP after link
* @hw: pointer to the HW structure
* @link_up: boolean flag for link up status
*
* at any other case.
*
* 82541_rev_2 & 82547_rev_2 have the capability to configure the DSP when a
* gigabit link is achieved to improve link quality.
*/
static s32
bool link_up)
{
DEBUGFUNC("e1000_config_dsp_after_link_change_82541");
if (link_up) {
if (ret_val) {
DEBUGOUT("Error getting link speed and duplex\n");
goto out;
}
if (speed != SPEED_1000) {
goto out;
}
if (ret_val)
goto out;
for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
dsp_reg_array[i],
&phy_data);
if (ret_val)
goto out;
dsp_reg_array[i],
phy_data);
if (ret_val)
goto out;
}
}
goto out;
}
/* clear previous idle error counts */
if (ret_val)
goto out;
for (i = 0; i < ffe_idle_err_timeout; i++) {
usec_delay(1000);
&phy_data);
if (ret_val)
goto out;
if (ret_val)
goto out;
break;
}
if (idle_errs)
}
} else {
/*
* Save off the current value of register 0x2F5B
* to be restored at the end of the routines.
*/
0x2F5B,
if (ret_val)
goto out;
/* Disable the PHY transmitter */
if (ret_val)
goto out;
msec_delay_irq(20);
0x0000,
if (ret_val)
goto out;
for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
dsp_reg_array[i],
&phy_data);
if (ret_val)
goto out;
dsp_reg_array[i],
phy_data);
if (ret_val)
goto out;
}
0x0000,
if (ret_val)
goto out;
msec_delay_irq(20);
/* Now enable the transmitter */
0x2F5B,
if (ret_val)
goto out;
}
goto out;
}
/*
* Save off the current value of register 0x2F5B
* to be restored at the end of the routines.
*/
if (ret_val)
goto out;
/* Disable the PHY transmitter */
if (ret_val)
goto out;
msec_delay_irq(20);
0x0000,
if (ret_val)
goto out;
if (ret_val)
goto out;
0x0000,
if (ret_val)
goto out;
msec_delay_irq(20);
/* Now enable the transmitter */
if (ret_val)
goto out;
}
out:
return (ret_val);
}
/*
* e1000_get_cable_length_igp_82541 - Determine cable length for igp PHY
* @hw: pointer to the HW structure
*
* The automatic gain control (agc) normalizes the amplitude of the
* received signal, adjusting for the attenuation produced by the
* cable. By reading the AGC registers, which represent the
* combination of coarse and fine gain value, the value can be put
* into a lookup table to obtain the approximate cable length
* for each channel.
*/
static s32
{
DEBUGFUNC("e1000_get_cable_length_igp_82541");
/* Read the AGC registers for all channels */
for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
if (ret_val)
goto out;
/* Bounds checking */
(cur_agc_value == 0)) {
ret_val = -E1000_ERR_PHY;
goto out;
}
if (min_agc_value > cur_agc_value)
}
/* Remove the minimal AGC result for length < 50m */
/* Average the three remaining channels for the length. */
} else {
/* Average the channels for the length. */
}
: 0;
out:
return (ret_val);
}
/*
* e1000_set_d3_lplu_state_82541 - Sets low power link up state for D3
* @hw: pointer to the HW structure
*
* Success returns 0, Failure returns 1
*
* The low power link up (lplu) state is set to the power management level D3
* and SmartSpeed is disabled when active is true, else clear lplu for D3
* and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU
* is used during Dx states where the power conservation is most important.
* During driver activity, SmartSpeed should be enabled so performance is
* maintained.
*/
static s32
{
DEBUGFUNC("e1000_set_d3_lplu_state_82541");
case e1000_82541_rev_2:
case e1000_82547_rev_2:
break;
default:
goto out;
}
if (ret_val)
goto out;
if (!active) {
if (ret_val)
goto out;
/*
* LPLU and SmartSpeed are mutually exclusive. LPLU is used
* during Dx states where the power conservation is most
* important. During driver activity we should enable
* SmartSpeed, so performance is maintained.
*/
&data);
if (ret_val)
goto out;
data);
if (ret_val)
goto out;
&data);
if (ret_val)
goto out;
data);
if (ret_val)
goto out;
}
if (ret_val)
goto out;
/* When LPLU is enabled, we should disable SmartSpeed */
&data);
if (ret_val)
goto out;
data);
}
out:
return (ret_val);
}
/*
* e1000_setup_led_82541 - Configures SW controllable LED
* @hw: pointer to the HW structure
*
* This prepares the SW controllable LED for use and saves the current state
* of the LED so it can be later restored.
*/
static s32
{
DEBUGFUNC("e1000_setup_led_82541");
&dev_spec->spd_default);
if (ret_val)
goto out;
if (ret_val)
goto out;
out:
return (ret_val);
}
/*
* e1000_cleanup_led_82541 - Set LED config to default operation
* @hw: pointer to the HW structure
*
* Remove the current LED configuration and set the LED configuration
* to the default value, saved from the EEPROM.
*/
static s32
{
DEBUGFUNC("e1000_cleanup_led_82541");
if (ret_val)
goto out;
out:
return (ret_val);
}
/*
* e1000_phy_init_script_82541 - Initialize GbE PHY
* @hw: pointer to the HW structure
*
* Initializes the IGP PHY.
*/
static s32
{
DEBUGFUNC("e1000_phy_init_script_82541");
if (!dev_spec->phy_init_script) {
goto out;
}
/* Delay after phy reset to enable NVM configuration to load */
msec_delay(20);
/*
* Save off the current value of register 0x2F5B to be restored at
* the end of this routine.
*/
/* Disabled the PHY transmitter */
msec_delay(20);
msec_delay(5);
case e1000_82541:
case e1000_82547:
break;
case e1000_82541_rev_2:
case e1000_82547_rev_2:
break;
default:
break;
}
msec_delay(20);
/* Now enable the transmitter */
/* Move to analog registers page */
&fused);
if (!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) {
&fused);
} else if (coarse ==
fused);
}
}
out:
return (ret_val);
}
/*
* @hw: pointer to the HW structure
*
* IGP PHY.
*/
void
{
DEBUGFUNC("e1000_init_script_state_82541");
DEBUGOUT("Initialization script not necessary.\n");
return;
}
}
/*
* e1000_fifo_workaround_82547 - Workaround for Tx fifo failure
* @hw: pointer to the HW structure
* @length: length of next outgoing frame
*
* Returns: E1000_ERR_FIFO_WRAP if the next packet cannot be transmitted yet
* E1000_SUCCESS if the next packet can be transmitted
*
* Workaround for the 82547 Tx fifo failure.
*/
{
DEBUGFUNC("e1000_fifo_workaround_82547");
goto out;
/*
* Get the length as seen by the FIFO of the next real
* packet to be transmitted.
*/
goto out;
goto out;
goto out;
}
goto out;
}
goto out;
}
/* Disable the tx unit to avoid further pointer movement */
/* Reset the fifo pointers. */
/* Re-enabling tx unit */
dev_spec->tx_fifo_head = 0;
out:
return (ret_val);
}
/*
* e1000_update_tx_fifo_head - Update Tx fifo head pointer
* @hw: pointer to the HW structure
* @length: length of next outgoing frame
*
* Updates the SW calculated Tx FIFO head pointer.
*/
void
{
DEBUGFUNC("e1000_update_tx_fifo_head_82547");
return;
}
/*
* @hw: pointer to the HW structure
*
* TTL workaround.
*/
void
{
DEBUGFUNC("e1000_set_ttl_workaround_state_82541");
return;
}
/*
* e1000_ttl_workaround_enabled_82541 - Returns current TTL workaround status
* @hw: pointer to the HW structure
*
* Returns the current status of the TTL workaround, as to whether the
* workaround is enabled or disabled.
*/
bool
{
bool state = false;
DEBUGFUNC("e1000_ttl_workaround_enabled_82541");
goto out;
out:
return (state);
}
/*
* e1000_igp_ttl_workaround_82547 - Workaround for long TTL on 100HD hubs
* @hw: pointer to the HW structure
*
* E1000_SUCCESS in any other case
*
* This function, specific to 82547 hardware only, needs to be called every
* second. It checks if a parallel detect fault has occurred. If a fault
* second). If link is established, stop the workaround and ensure the DSP
* reset is enabled.
*/
{
bool link;
DEBUGFUNC("e1000_igp_ttl_workaround_82547");
/* The workaround needed only for B-0 silicon HW */
goto out;
if (!(e1000_ttl_workaround_enabled_82541(hw)))
goto out;
/* Check for link first */
if (ret_val)
goto out;
if (link) {
/*
* If link is established during the workaround,
* the DSP mechanism must be enabled.
*/
if (dev_spec->dsp_reset_counter) {
dev_spec->dsp_reset_counter = 0;
} else {
goto out;
}
} else {
if (dev_spec->dsp_reset_counter == 0) {
/*
* Workaround not activated,
* check if it needs activation
*/
&phy_data);
if (ret_val)
goto out;
/*
* Activate the workaround if there was a
* parallel detect fault
*/
if (phy_data & NWAY_ER_PAR_DETECT_FAULT) {
} else {
goto out;
}
}
/* After 5 times, stop the workaround */
dev_spec->dsp_reset_counter = 0;
} else {
if (dev_spec->dsp_reset_counter) {
}
}
}
ret_val =
out:
return (ret_val);
}
/*
* e1000_power_down_phy_copper_82541 - Remove link in case of PHY power down
* @hw: pointer to the HW structure
*
* In the case of a PHY power down to save power, or to turn off link during a
* driver unload, or wake on lan is not enabled, remove the link.
*/
static void
{
/* If the management interface is not enabled, then power down */
}
/*
* e1000_clear_hw_cntrs_82541 - Clear device specific hardware counters
* @hw: pointer to the HW structure
*
* Clears the hardware counters by reading the counter registers.
*/
static void
{
DEBUGFUNC("e1000_clear_hw_cntrs_82541");
}