view usr/src/uts/common/io/e1000g/e1000_82541.c @ 10680:45bda3640f27

6797885 need to add support for network device (8086,10ea) in a new Intel system 6803799 need to add network device support (8086,10ef) for a new Intel system 6808388 e1000g inteface experience packet lost when switch between joining and leaving a multicast stream
author Miles Xu, Sun Microsystems <Min.Xu@Sun.COM>
date Tue, 29 Sep 2009 12:12:23 +0800
parents 4086dd59e147
children e0feef27b61a
line wrap: on
line source

/*
 * 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
 *	http://www.opensolaris.org/os/licensing.
 * 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-3_2009-8-20
 */

/*
 * 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"

static s32 e1000_init_phy_params_82541(struct e1000_hw *hw);
static s32 e1000_init_nvm_params_82541(struct e1000_hw *hw);
static s32 e1000_init_mac_params_82541(struct e1000_hw *hw);
static s32 e1000_reset_hw_82541(struct e1000_hw *hw);
static s32 e1000_init_hw_82541(struct e1000_hw *hw);
static s32 e1000_get_link_up_info_82541(struct e1000_hw *hw, u16 *speed,
    u16 *duplex);
static s32 e1000_phy_hw_reset_82541(struct e1000_hw *hw);
static s32 e1000_setup_copper_link_82541(struct e1000_hw *hw);
static s32 e1000_check_for_link_82541(struct e1000_hw *hw);
static s32 e1000_get_cable_length_igp_82541(struct e1000_hw *hw);
static s32 e1000_set_d3_lplu_state_82541(struct e1000_hw *hw,
    bool active);
static s32 e1000_setup_led_82541(struct e1000_hw *hw);
static s32 e1000_cleanup_led_82541(struct e1000_hw *hw);
static void e1000_clear_hw_cntrs_82541(struct e1000_hw *hw);
static s32 e1000_config_dsp_after_link_change_82541(struct e1000_hw *hw,
    bool link_up);
static s32 e1000_phy_init_script_82541(struct e1000_hw *hw);
static void e1000_power_down_phy_copper_82541(struct e1000_hw *hw);

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
e1000_init_phy_params_82541(struct e1000_hw *hw)
{
	struct e1000_phy_info *phy = &hw->phy;
	s32 ret_val = E1000_SUCCESS;

	DEBUGFUNC("e1000_init_phy_params_82541");

	phy->addr = 1;
	phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
	phy->reset_delay_us = 10000;
	phy->type = e1000_phy_igp;

	/* Function Pointers */
	phy->ops.check_polarity = e1000_check_polarity_igp;
	phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp;
	phy->ops.get_cable_length = e1000_get_cable_length_igp_82541;
	phy->ops.get_cfg_done = e1000_get_cfg_done_generic;
	phy->ops.get_info = e1000_get_phy_info_igp;
	phy->ops.read_reg = e1000_read_phy_reg_igp;
	phy->ops.reset = e1000_phy_hw_reset_82541;
	phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_82541;
	phy->ops.write_reg = e1000_write_phy_reg_igp;
	phy->ops.power_up = e1000_power_up_phy_copper;
	phy->ops.power_down = e1000_power_down_phy_copper_82541;

	ret_val = e1000_get_phy_id(hw);
	if (ret_val)
		goto out;

	/* Verify phy id */
	if (phy->id != IGP01E1000_I_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
e1000_init_nvm_params_82541(struct e1000_hw *hw)
{
	struct e1000_nvm_info *nvm = &hw->nvm;
	s32 ret_val = E1000_SUCCESS;
	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
	u16 size;

	DEBUGFUNC("e1000_init_nvm_params_82541");

	switch (nvm->override) {
	case e1000_nvm_override_spi_large:
		nvm->type = e1000_nvm_eeprom_spi;
		eecd |= E1000_EECD_ADDR_BITS;
		break;
	case e1000_nvm_override_spi_small:
		nvm->type = e1000_nvm_eeprom_spi;
		eecd &= ~E1000_EECD_ADDR_BITS;
		break;
	case e1000_nvm_override_microwire_large:
		nvm->type = e1000_nvm_eeprom_microwire;
		eecd |= E1000_EECD_SIZE;
		break;
	case e1000_nvm_override_microwire_small:
		nvm->type = e1000_nvm_eeprom_microwire;
		eecd &= ~E1000_EECD_SIZE;
		break;
	default:
		nvm->type = eecd & E1000_EECD_TYPE
		    ? e1000_nvm_eeprom_spi
		    : e1000_nvm_eeprom_microwire;
		break;
	}

	if (nvm->type == e1000_nvm_eeprom_spi) {
		nvm->address_bits = (eecd & E1000_EECD_ADDR_BITS)
		    ? 16 : 8;
		nvm->delay_usec = 1;
		nvm->opcode_bits = 8;
		nvm->page_size = (eecd & E1000_EECD_ADDR_BITS)
		    ? 32 : 8;

		/* Function Pointers */
		nvm->ops.acquire = e1000_acquire_nvm_generic;
		nvm->ops.read = e1000_read_nvm_spi;
		nvm->ops.release = e1000_release_nvm_generic;
		nvm->ops.update = e1000_update_nvm_checksum_generic;
		nvm->ops.valid_led_default = e1000_valid_led_default_generic;
		nvm->ops.validate = e1000_validate_nvm_checksum_generic;
		nvm->ops.write = e1000_write_nvm_spi;

		/*
		 * 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.
		 */
		nvm->word_size = 64;
		ret_val = nvm->ops.read(hw, NVM_CFG, 1, &size);
		if (ret_val)
			goto out;
		size = (size & NVM_SIZE_MASK) >> NVM_SIZE_SHIFT;
		/*
		 * 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) {
			size += NVM_WORD_SIZE_BASE_SHIFT_82541;
			nvm->word_size = 1 << size;
		}
	} else {
		nvm->address_bits = (eecd & E1000_EECD_ADDR_BITS)
		    ? 8 : 6;
		nvm->delay_usec = 50;
		nvm->opcode_bits = 3;
		nvm->word_size = (eecd & E1000_EECD_ADDR_BITS)
		    ? 256 : 64;

		/* Function Pointers */
		nvm->ops.acquire = e1000_acquire_nvm_generic;
		nvm->ops.read = e1000_read_nvm_microwire;
		nvm->ops.release = e1000_release_nvm_generic;
		nvm->ops.update = e1000_update_nvm_checksum_generic;
		nvm->ops.valid_led_default = e1000_valid_led_default_generic;
		nvm->ops.validate = e1000_validate_nvm_checksum_generic;
		nvm->ops.write = e1000_write_nvm_microwire;
	}

out:
	return (ret_val);
}

/*
 * e1000_init_mac_params_82541 - Init MAC func ptrs.
 * @hw: pointer to the HW structure
 */
static s32
e1000_init_mac_params_82541(struct e1000_hw *hw)
{
	struct e1000_mac_info *mac = &hw->mac;

	DEBUGFUNC("e1000_init_mac_params_82541");

	/* Set media type */
	hw->phy.media_type = e1000_media_type_copper;
	/* Set mta register count */
	mac->mta_reg_count = 128;
	/* Set rar entry count */
	mac->rar_entry_count = E1000_RAR_ENTRIES;
	/* Set if part includes ASF firmware */
	mac->asf_firmware_present = true;

	/* Function Pointers */

	/* bus type/speed/width */
	mac->ops.get_bus_info = e1000_get_bus_info_pci_generic;
	/* function id */
	mac->ops.set_lan_id = e1000_set_lan_id_single_port;
	/* reset */
	mac->ops.reset_hw = e1000_reset_hw_82541;
	/* hw initialization */
	mac->ops.init_hw = e1000_init_hw_82541;
	/* link setup */
	mac->ops.setup_link = e1000_setup_link_generic;
	/* physical interface link setup */
	mac->ops.setup_physical_interface = e1000_setup_copper_link_82541;
	/* check for link */
	mac->ops.check_for_link = e1000_check_for_link_82541;
	/* link info */
	mac->ops.get_link_up_info = e1000_get_link_up_info_82541;
	/* multicast address update */
	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
	/* writing VFTA */
	mac->ops.write_vfta = e1000_write_vfta_generic;
	/* clearing VFTA */
	mac->ops.clear_vfta = e1000_clear_vfta_generic;
	/* setting MTA */
	mac->ops.mta_set = e1000_mta_set_generic;
	/* ID LED init */
	mac->ops.id_led_init = e1000_id_led_init_generic;
	/* setup LED */
	mac->ops.setup_led = e1000_setup_led_82541;
	/* cleanup LED */
	mac->ops.cleanup_led = e1000_cleanup_led_82541;
	/* turn on/off LED */
	mac->ops.led_on = e1000_led_on_generic;
	mac->ops.led_off = e1000_led_off_generic;
	/* clear hardware counters */
	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82541;

	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
e1000_init_function_pointers_82541(struct e1000_hw *hw)
{
	DEBUGFUNC("e1000_init_function_pointers_82541");

	hw->mac.ops.init_params = e1000_init_mac_params_82541;
	hw->nvm.ops.init_params = e1000_init_nvm_params_82541;
	hw->phy.ops.init_params = e1000_init_phy_params_82541;
}

/*
 * e1000_reset_hw_82541 - Reset hardware
 * @hw: pointer to the HW structure
 *
 * This resets the hardware into a known state.
 */
static s32
e1000_reset_hw_82541(struct e1000_hw *hw)
{
	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
	u32 ledctl, ctrl, manc;

	DEBUGFUNC("e1000_reset_hw_82541");

	DEBUGOUT("Masking off all interrupts\n");
	E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF);

	E1000_WRITE_REG(hw, E1000_RCTL, 0);
	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
	E1000_WRITE_FLUSH(hw);

	dev_spec->tx_fifo_head = 0;

	/*
	 * Delay to allow any outstanding PCI transactions to complete
	 * before resetting the device.
	 */
	msec_delay(10);

	ctrl = E1000_READ_REG(hw, E1000_CTRL);

	/* Must reset the Phy before resetting the MAC */
	if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {
		E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_PHY_RST));
		msec_delay(5);
	}

	DEBUGOUT("Issuing a global reset to 82541/82547 MAC\n");
	switch (hw->mac.type) {
	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.
		 */
		E1000_WRITE_REG_IO(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
		break;
	default:
		E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
		break;
	}

	/* Wait for NVM reload */
	msec_delay(20);

	/* Disable HW ARPs on ASF enabled adapters */
	manc = E1000_READ_REG(hw, E1000_MANC);
	manc &= ~E1000_MANC_ARP_EN;
	E1000_WRITE_REG(hw, E1000_MANC, manc);

	if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {
		(void) e1000_phy_init_script_82541(hw);

		/* Configure activity LED after Phy reset */
		ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
		ledctl &= IGP_ACTIVITY_LED_MASK;
		ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
		E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
	}

	/* Once again, mask the interrupts */
	DEBUGOUT("Masking off all interrupts\n");
	E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF);

	/* Clear any pending interrupt events. */
	(void) E1000_READ_REG(hw, E1000_ICR);

	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
e1000_init_hw_82541(struct e1000_hw *hw)
{
	struct e1000_mac_info *mac = &hw->mac;
	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
	u32 pba;
	u32 i, txdctl;
	s32 ret_val;

	DEBUGFUNC("e1000_init_hw_82541");

	/* Initialize identification LED */
	ret_val = mac->ops.id_led_init(hw);
	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 */
	ret_val = hw->phy.ops.read_reg(hw,
	    IGP01E1000_GMII_FIFO,
	    &dev_spec->spd_default);
	if (ret_val)
		goto out;

	pba = E1000_READ_REG(hw, E1000_PBA);
	dev_spec->tx_fifo_start = (pba & 0x0000FFFF) * E1000_FIFO_MULTIPLIER;
	dev_spec->tx_fifo_size = (pba & 0xFFFF0000) >> 6;

	/* Disabling VLAN filtering */
	DEBUGOUT("Initializing the IEEE VLAN\n");
	mac->ops.clear_vfta(hw);

	/* Setup the receive address. */
	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);

	/* Zero out the Multicast HASH table */
	DEBUGOUT("Zeroing the MTA\n");
	for (i = 0; i < mac->mta_reg_count; i++) {
		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
		/*
		 * 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.
		 */
		E1000_WRITE_FLUSH(hw);
	}

	/* Setup link and flow control */
	ret_val = mac->ops.setup_link(hw);

	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
	    E1000_TXDCTL_FULL_TX_DESC_WB;
	E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);

	/*
	 * 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.
	 */
	e1000_clear_hw_cntrs_82541(hw);

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
e1000_get_link_up_info_82541(struct e1000_hw *hw, u16 *speed, u16 *duplex)
{
	struct e1000_phy_info *phy = &hw->phy;
	s32 ret_val;
	u16 data;

	DEBUGFUNC("e1000_get_link_up_info_82541");

	ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex);
	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.
	 */
	ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_EXP, &data);
	if (ret_val)
		goto out;

	if (!(data & NWAY_ER_LP_NWAY_CAPS)) {
		*duplex = HALF_DUPLEX;
	} else {
		ret_val = phy->ops.read_reg(hw, PHY_LP_ABILITY, &data);
		if (ret_val)
			goto out;

		if (*speed == SPEED_100) {
			if (!(data & NWAY_LPAR_100TX_FD_CAPS))
				*duplex = HALF_DUPLEX;
		} else if (*speed == SPEED_10) {
			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
 * semaphore (if necessary) and read/set/write the device control reset
 * bit in the PHY.  Wait the appropriate delay time for the device to
 * reset and release the semaphore (if necessary).
 */
static s32
e1000_phy_hw_reset_82541(struct e1000_hw *hw)
{
	s32 ret_val;
	u32 ledctl;

	DEBUGFUNC("e1000_phy_hw_reset_82541");

	ret_val = e1000_phy_hw_reset_generic(hw);
	if (ret_val)
		goto out;

	(void) e1000_phy_init_script_82541(hw);

	if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {
		/* Configure activity LED after PHY reset */
		ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
		ledctl &= IGP_ACTIVITY_LED_MASK;
		ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
		E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
	}

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
e1000_setup_copper_link_82541(struct e1000_hw *hw)
{
	struct e1000_phy_info *phy = &hw->phy;
	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
	s32 ret_val;
	u32 ctrl, ledctl;

	DEBUGFUNC("e1000_setup_copper_link_82541");

	ctrl = E1000_READ_REG(hw, E1000_CTRL);
	ctrl |= E1000_CTRL_SLU;
	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);

	hw->phy.reset_disable = false;

	/* Earlier revs of the IGP phy require us to force MDI. */
	if (hw->mac.type == e1000_82541 || hw->mac.type == e1000_82547) {
		dev_spec->dsp_config = e1000_dsp_config_disabled;
		phy->mdix = 1;
	} else {
		dev_spec->dsp_config = e1000_dsp_config_enabled;
	}

	ret_val = e1000_copper_link_setup_igp(hw);
	if (ret_val)
		goto out;

	if (hw->mac.autoneg) {
		if (dev_spec->ffe_config == e1000_ffe_config_active)
			dev_spec->ffe_config = e1000_ffe_config_enabled;
	}

	/* Configure activity LED after Phy reset */
	ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
	ledctl &= IGP_ACTIVITY_LED_MASK;
	ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
	E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);

	ret_val = e1000_setup_copper_link_generic(hw);

out:
	return (ret_val);
}

/*
 * e1000_check_for_link_82541 - Check/Store link connection
 * @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
e1000_check_for_link_82541(struct e1000_hw *hw)
{
	struct e1000_mac_info *mac = &hw->mac;
	s32 ret_val;
	bool link;

	DEBUGFUNC("e1000_check_for_link_82541");

	/*
	 * We only want to go out to the PHY registers to see if Auto-Neg
	 * has completed and/or if our link status has changed.  The
	 * 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;
	}

	/*
	 * First we want to see if the MII Status Register reports
	 * link.  If so, then we want to get the current speed/duplex
	 * of the PHY.
	 */
	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
	if (ret_val)
		goto out;

	if (!link) {
		ret_val = e1000_config_dsp_after_link_change_82541(hw, false);
		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);

	/*
	 * 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;
	}

	ret_val = e1000_config_dsp_after_link_change_82541(hw, true);

	/*
	 * Auto-Neg is enabled.  Auto Speed Detection takes care
	 * of MAC speed/duplex configuration.  So we only need to
	 * configure Collision Distance in the MAC.
	 */
	e1000_config_collision_dist_generic(hw);

	/*
	 * 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.
	 */
	ret_val = e1000_config_fc_after_link_up_generic(hw);
	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
 *
 * Return E1000_ERR_PHY when failing to read/write the PHY, else E1000_SUCCESS
 * 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
e1000_config_dsp_after_link_change_82541(struct e1000_hw *hw,
    bool link_up)
{
	struct e1000_phy_info *phy = &hw->phy;
	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
	s32 ret_val;
	u32 idle_errs = 0;
	u16 phy_data, phy_saved_data, speed, duplex, i;
	u16 ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_20;
	u16 dsp_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
	{IGP01E1000_PHY_AGC_PARAM_A,
		IGP01E1000_PHY_AGC_PARAM_B,
		IGP01E1000_PHY_AGC_PARAM_C,
	IGP01E1000_PHY_AGC_PARAM_D};

	DEBUGFUNC("e1000_config_dsp_after_link_change_82541");

	if (link_up) {
		ret_val = hw->mac.ops.get_link_up_info(hw, &speed, &duplex);
		if (ret_val) {
			DEBUGOUT("Error getting link speed and duplex\n");
			goto out;
		}

		if (speed != SPEED_1000) {
			ret_val = E1000_SUCCESS;
			goto out;
		}

		ret_val = phy->ops.get_cable_length(hw);
		if (ret_val)
			goto out;

		if ((dev_spec->dsp_config == e1000_dsp_config_enabled) &&
		    phy->min_cable_length >= 50) {

			for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
				ret_val = phy->ops.read_reg(hw,
				    dsp_reg_array[i],
				    &phy_data);
				if (ret_val)
					goto out;

				phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;

				ret_val = phy->ops.write_reg(hw,
				    dsp_reg_array[i],
				    phy_data);
				if (ret_val)
					goto out;
			}
			dev_spec->dsp_config = e1000_dsp_config_activated;
		}

		if ((dev_spec->ffe_config != e1000_ffe_config_enabled) ||
		    (phy->min_cable_length >= 50)) {
			ret_val = E1000_SUCCESS;
			goto out;
		}

		/* clear previous idle error counts */
		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data);
		if (ret_val)
			goto out;

		for (i = 0; i < ffe_idle_err_timeout; i++) {
			usec_delay(1000);
			ret_val = phy->ops.read_reg(hw,
			    PHY_1000T_STATUS,
			    &phy_data);
			if (ret_val)
				goto out;

			idle_errs += (phy_data & SR_1000T_IDLE_ERROR_CNT);
			if (idle_errs > SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT) {
				dev_spec->ffe_config = e1000_ffe_config_active;

				ret_val = phy->ops.write_reg(hw,
				    IGP01E1000_PHY_DSP_FFE,
				    IGP01E1000_PHY_DSP_FFE_CM_CP);
				if (ret_val)
					goto out;
				break;
			}

			if (idle_errs)
				ffe_idle_err_timeout =
				    FFE_IDLE_ERR_COUNT_TIMEOUT_100;
		}
	} else {
		if (dev_spec->dsp_config == e1000_dsp_config_activated) {
			/*
			 * Save off the current value of register 0x2F5B
			 * to be restored at the end of the routines.
			 */
			ret_val = phy->ops.read_reg(hw,
			    0x2F5B,
			    &phy_saved_data);
			if (ret_val)
				goto out;

			/* Disable the PHY transmitter */
			ret_val = phy->ops.write_reg(hw, 0x2F5B, 0x0003);
			if (ret_val)
				goto out;

			msec_delay_irq(20);

			ret_val = phy->ops.write_reg(hw,
			    0x0000,
			    IGP01E1000_IEEE_FORCE_GIG);
			if (ret_val)
				goto out;
			for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
				ret_val = phy->ops.read_reg(hw,
				    dsp_reg_array[i],
				    &phy_data);
				if (ret_val)
					goto out;

				phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
				phy_data |= IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS;

				ret_val = phy->ops.write_reg(hw,
				    dsp_reg_array[i],
				    phy_data);
				if (ret_val)
					goto out;
			}

			ret_val = phy->ops.write_reg(hw,
			    0x0000,
			    IGP01E1000_IEEE_RESTART_AUTONEG);
			if (ret_val)
				goto out;

			msec_delay_irq(20);

			/* Now enable the transmitter */
			ret_val = phy->ops.write_reg(hw,
			    0x2F5B,
			    phy_saved_data);
			if (ret_val)
				goto out;

			dev_spec->dsp_config = e1000_dsp_config_enabled;
		}

		if (dev_spec->ffe_config != e1000_ffe_config_active) {
			ret_val = E1000_SUCCESS;
			goto out;
		}

		/*
		 * Save off the current value of register 0x2F5B
		 * to be restored at the end of the routines.
		 */
		ret_val = phy->ops.read_reg(hw, 0x2F5B, &phy_saved_data);
		if (ret_val)
			goto out;

		/* Disable the PHY transmitter */
		ret_val = phy->ops.write_reg(hw, 0x2F5B, 0x0003);
		if (ret_val)
			goto out;

		msec_delay_irq(20);

		ret_val = phy->ops.write_reg(hw,
		    0x0000,
		    IGP01E1000_IEEE_FORCE_GIG);
		if (ret_val)
			goto out;

		ret_val = phy->ops.write_reg(hw,
		    IGP01E1000_PHY_DSP_FFE,
		    IGP01E1000_PHY_DSP_FFE_DEFAULT);
		if (ret_val)
			goto out;

		ret_val = phy->ops.write_reg(hw,
		    0x0000,
		    IGP01E1000_IEEE_RESTART_AUTONEG);
		if (ret_val)
			goto out;

		msec_delay_irq(20);

		/* Now enable the transmitter */
		ret_val = phy->ops.write_reg(hw, 0x2F5B, phy_saved_data);

		if (ret_val)
			goto out;

		dev_spec->ffe_config = e1000_ffe_config_enabled;
	}

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
e1000_get_cable_length_igp_82541(struct e1000_hw *hw)
{
	struct e1000_phy_info *phy = &hw->phy;
	s32 ret_val = E1000_SUCCESS;
	u16 i, data;
	u16 cur_agc_value, agc_value = 0;
	u16 min_agc_value = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
	u16 agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
	{IGP01E1000_PHY_AGC_A,
		IGP01E1000_PHY_AGC_B,
		IGP01E1000_PHY_AGC_C,
	IGP01E1000_PHY_AGC_D};

	DEBUGFUNC("e1000_get_cable_length_igp_82541");

	/* Read the AGC registers for all channels */
	for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
		ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &data);
		if (ret_val)
			goto out;

		cur_agc_value = data >> IGP01E1000_AGC_LENGTH_SHIFT;

		/* Bounds checking */
		if ((cur_agc_value >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) ||
		    (cur_agc_value == 0)) {
			ret_val = -E1000_ERR_PHY;
			goto out;
		}

		agc_value += cur_agc_value;

		if (min_agc_value > cur_agc_value)
			min_agc_value = cur_agc_value;
	}

	/* Remove the minimal AGC result for length < 50m */
	if (agc_value < IGP01E1000_PHY_CHANNEL_NUM * 50) {
		agc_value -= min_agc_value;
		/* Average the three remaining channels for the length. */
		agc_value /= (IGP01E1000_PHY_CHANNEL_NUM - 1);
	} else {
		/* Average the channels for the length. */
		agc_value /= IGP01E1000_PHY_CHANNEL_NUM;
	}

	phy->min_cable_length = (e1000_igp_cable_length_table[agc_value] >
	    IGP01E1000_AGC_RANGE)
	    ? (e1000_igp_cable_length_table[agc_value] -
	    IGP01E1000_AGC_RANGE)
	    : 0;
	phy->max_cable_length = e1000_igp_cable_length_table[agc_value] +
	    IGP01E1000_AGC_RANGE;

	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;

out:
	return (ret_val);
}

/*
 * e1000_set_d3_lplu_state_82541 - Sets low power link up state for D3
 * @hw: pointer to the HW structure
 * @active: boolean used to enable/disable lplu
 *
 * 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
e1000_set_d3_lplu_state_82541(struct e1000_hw *hw, bool active)
{
	struct e1000_phy_info *phy = &hw->phy;
	s32 ret_val;
	u16 data;

	DEBUGFUNC("e1000_set_d3_lplu_state_82541");

	switch (hw->mac.type) {
	case e1000_82541_rev_2:
	case e1000_82547_rev_2:
		break;
	default:
		ret_val = e1000_set_d3_lplu_state_generic(hw, active);
		goto out;
	}

	ret_val = phy->ops.read_reg(hw, IGP01E1000_GMII_FIFO, &data);
	if (ret_val)
		goto out;

	if (!active) {
		data &= ~IGP01E1000_GMII_FLEX_SPD;
		ret_val = phy->ops.write_reg(hw, IGP01E1000_GMII_FIFO, data);
		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.
		 */
		if (phy->smart_speed == e1000_smart_speed_on) {
			ret_val = phy->ops.read_reg(hw,
			    IGP01E1000_PHY_PORT_CONFIG,
			    &data);
			if (ret_val)
				goto out;

			data |= IGP01E1000_PSCFR_SMART_SPEED;
			ret_val = phy->ops.write_reg(hw,
			    IGP01E1000_PHY_PORT_CONFIG,
			    data);
			if (ret_val)
				goto out;
		} 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;

			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
			ret_val = phy->ops.write_reg(hw,
			    IGP01E1000_PHY_PORT_CONFIG,
			    data);
			if (ret_val)
				goto out;
		}
	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
	    (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
	    (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
		data |= IGP01E1000_GMII_FLEX_SPD;
		ret_val = phy->ops.write_reg(hw, IGP01E1000_GMII_FIFO, data);
		if (ret_val)
			goto out;

		/* 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;

		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
		ret_val = phy->ops.write_reg(hw,
		    IGP01E1000_PHY_PORT_CONFIG,
		    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
e1000_setup_led_82541(struct e1000_hw *hw)
{
	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
	s32 ret_val;

	DEBUGFUNC("e1000_setup_led_82541");

	ret_val = hw->phy.ops.read_reg(hw,
	    IGP01E1000_GMII_FIFO,
	    &dev_spec->spd_default);
	if (ret_val)
		goto out;

	ret_val = hw->phy.ops.write_reg(hw,
	    IGP01E1000_GMII_FIFO,
	    (u16)(dev_spec->spd_default &
	    ~IGP01E1000_GMII_SPD));
	if (ret_val)
		goto out;

	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);

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
e1000_cleanup_led_82541(struct e1000_hw *hw)
{
	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
	s32 ret_val;

	DEBUGFUNC("e1000_cleanup_led_82541");

	ret_val = hw->phy.ops.write_reg(hw,
	    IGP01E1000_GMII_FIFO,
	    dev_spec->spd_default);
	if (ret_val)
		goto out;

	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);

out:
	return (ret_val);
}

/*
 * e1000_phy_init_script_82541 - Initialize GbE PHY
 * @hw: pointer to the HW structure
 *
 * Initializes the IGP PHY.
 */
static s32
e1000_phy_init_script_82541(struct e1000_hw *hw)
{
	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
	u32 ret_val;
	u16 phy_saved_data;

	DEBUGFUNC("e1000_phy_init_script_82541");

	if (!dev_spec->phy_init_script) {
		ret_val = E1000_SUCCESS;
		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.
	 */
	ret_val = hw->phy.ops.read_reg(hw, 0x2F5B, &phy_saved_data);

	/* Disabled the PHY transmitter */
	hw->phy.ops.write_reg(hw, 0x2F5B, 0x0003);

	msec_delay(20);

	hw->phy.ops.write_reg(hw, 0x0000, 0x0140);

	msec_delay(5);

	switch (hw->mac.type) {
	case e1000_82541:
	case e1000_82547:
		hw->phy.ops.write_reg(hw, 0x1F95, 0x0001);

		hw->phy.ops.write_reg(hw, 0x1F71, 0xBD21);

		hw->phy.ops.write_reg(hw, 0x1F79, 0x0018);

		hw->phy.ops.write_reg(hw, 0x1F30, 0x1600);

		hw->phy.ops.write_reg(hw, 0x1F31, 0x0014);

		hw->phy.ops.write_reg(hw, 0x1F32, 0x161C);

		hw->phy.ops.write_reg(hw, 0x1F94, 0x0003);

		hw->phy.ops.write_reg(hw, 0x1F96, 0x003F);

		hw->phy.ops.write_reg(hw, 0x2010, 0x0008);
		break;
	case e1000_82541_rev_2:
	case e1000_82547_rev_2:
		hw->phy.ops.write_reg(hw, 0x1F73, 0x0099);
		break;
	default:
		break;
	}

	hw->phy.ops.write_reg(hw, 0x0000, 0x3300);

	msec_delay(20);

	/* Now enable the transmitter */
	hw->phy.ops.write_reg(hw, 0x2F5B, phy_saved_data);

	if (hw->mac.type == e1000_82547) {
		u16 fused, fine, coarse;

		/* Move to analog registers page */
		hw->phy.ops.read_reg(hw,
		    IGP01E1000_ANALOG_SPARE_FUSE_STATUS,
		    &fused);

		if (!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) {
			hw->phy.ops.read_reg(hw,
			    IGP01E1000_ANALOG_FUSE_STATUS,
			    &fused);

			fine = fused & IGP01E1000_ANALOG_FUSE_FINE_MASK;
			coarse = fused & IGP01E1000_ANALOG_FUSE_COARSE_MASK;

			if (coarse > IGP01E1000_ANALOG_FUSE_COARSE_THRESH) {
				coarse -= IGP01E1000_ANALOG_FUSE_COARSE_10;
				fine -= IGP01E1000_ANALOG_FUSE_FINE_1;
			} else if (coarse ==
			    IGP01E1000_ANALOG_FUSE_COARSE_THRESH)
				fine -= IGP01E1000_ANALOG_FUSE_FINE_10;

			fused = (fused & IGP01E1000_ANALOG_FUSE_POLY_MASK) |
			    (fine & IGP01E1000_ANALOG_FUSE_FINE_MASK) |
			    (coarse & IGP01E1000_ANALOG_FUSE_COARSE_MASK);

			hw->phy.ops.write_reg(hw,
			    IGP01E1000_ANALOG_FUSE_CONTROL,
			    fused);
			hw->phy.ops.write_reg(hw,
			    IGP01E1000_ANALOG_FUSE_BYPASS,
			    IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL);
		}
	}

out:
	return (ret_val);
}

/*
 * e1000_init_script_state_82541 - Enable/Disable PHY init script
 * @hw: pointer to the HW structure
 * @state: boolean value used to enable/disable PHY init script
 *
 * Allows the driver to enable/disable the PHY init script, if the PHY is an
 * IGP PHY.
 */
void
e1000_init_script_state_82541(struct e1000_hw *hw, bool state)
{
	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;

	DEBUGFUNC("e1000_init_script_state_82541");

	if (hw->phy.type != e1000_phy_igp) {
		DEBUGOUT("Initialization script not necessary.\n");
		return;
	}

	dev_spec->phy_init_script = state;
}

/*
 * 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.
 */
s32
e1000_fifo_workaround_82547(struct e1000_hw *hw, u16 length)
{
	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
	u32 tctl;
	s32 ret_val = E1000_SUCCESS;
	u16 fifo_pkt_len;

	DEBUGFUNC("e1000_fifo_workaround_82547");

	if (hw->mac.type != e1000_82547)
		goto out;

	/*
	 * Get the length as seen by the FIFO of the next real
	 * packet to be transmitted.
	 */
	fifo_pkt_len = E1000_ROUNDUP(length + E1000_FIFO_HDR_SIZE,
	    E1000_FIFO_GRANULARITY);

	if (fifo_pkt_len <= (E1000_FIFO_PAD_82547 + E1000_FIFO_HDR_SIZE))
		goto out;

	if ((dev_spec->tx_fifo_head + fifo_pkt_len) <
	    (dev_spec->tx_fifo_size + E1000_FIFO_PAD_82547))
		goto out;

	if (E1000_READ_REG(hw, E1000_TDT(0)) !=
	    E1000_READ_REG(hw, E1000_TDH(0))) {
		ret_val = -E1000_ERR_FIFO_WRAP;
		goto out;
	}

	if (E1000_READ_REG(hw, E1000_TDFT) != E1000_READ_REG(hw, E1000_TDFH)) {
		ret_val = -E1000_ERR_FIFO_WRAP;
		goto out;
	}

	if (E1000_READ_REG(hw, E1000_TDFTS) !=
	    E1000_READ_REG(hw, E1000_TDFHS)) {
		ret_val = -E1000_ERR_FIFO_WRAP;
		goto out;
	}

	/* Disable the tx unit to avoid further pointer movement */
	tctl = E1000_READ_REG(hw, E1000_TCTL);
	E1000_WRITE_REG(hw, E1000_TCTL, tctl & ~E1000_TCTL_EN);

	/* Reset the fifo pointers. */
	E1000_WRITE_REG(hw, E1000_TDFT, dev_spec->tx_fifo_start);
	E1000_WRITE_REG(hw, E1000_TDFH, dev_spec->tx_fifo_start);
	E1000_WRITE_REG(hw, E1000_TDFTS, dev_spec->tx_fifo_start);
	E1000_WRITE_REG(hw, E1000_TDFHS, dev_spec->tx_fifo_start);

	/* Re-enabling tx unit */
	E1000_WRITE_REG(hw, E1000_TCTL, tctl);
	E1000_WRITE_FLUSH(hw);

	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
e1000_update_tx_fifo_head_82547(struct e1000_hw *hw, u32 length)
{
	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;

	DEBUGFUNC("e1000_update_tx_fifo_head_82547");

	if (hw->mac.type != e1000_82547)
		return;

	dev_spec->tx_fifo_head += E1000_ROUNDUP(length + E1000_FIFO_HDR_SIZE,
	    E1000_FIFO_GRANULARITY);

	if (dev_spec->tx_fifo_head > dev_spec->tx_fifo_size)
		dev_spec->tx_fifo_head -= dev_spec->tx_fifo_size;
}

/*
 * e1000_set_ttl_workaround_state_82541 - Enable/Disables TTL workaround
 * @hw: pointer to the HW structure
 * @state: boolean to enable/disable TTL workaround
 *
 * For 82541 or 82547 only silicon, allows the driver to enable/disable the
 * TTL workaround.
 */
void
e1000_set_ttl_workaround_state_82541(struct e1000_hw *hw, bool state)
{
	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;

	DEBUGFUNC("e1000_set_ttl_workaround_state_82541");

	if ((hw->mac.type != e1000_82541) && (hw->mac.type != e1000_82547))
		return;

	dev_spec->ttl_workaround = state;
}

/*
 * 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
e1000_ttl_workaround_enabled_82541(struct e1000_hw *hw)
{
	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
	bool state = false;

	DEBUGFUNC("e1000_ttl_workaround_enabled_82541");

	if ((hw->mac.type != e1000_82541) && (hw->mac.type != e1000_82547))
		goto out;

	state = dev_spec->ttl_workaround;

out:
	return (state);
}

/*
 * e1000_igp_ttl_workaround_82547 - Workaround for long TTL on 100HD hubs
 * @hw: pointer to the HW structure
 *
 * Returns: E1000_ERR_PHY if fail to read/write the PHY
 *          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
 * occurred, disable/enable the DSP reset mechanism up to 5 times (once per
 * second).  If link is established, stop the workaround and ensure the DSP
 * reset is enabled.
 */
s32
e1000_igp_ttl_workaround_82547(struct e1000_hw *hw)
{
	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
	s32 ret_val = E1000_SUCCESS;
	u16 phy_data = 0;
	u16 dsp_value = DSP_RESET_ENABLE;
	bool link;

	DEBUGFUNC("e1000_igp_ttl_workaround_82547");

	/* The workaround needed only for B-0 silicon HW */
	if ((hw->mac.type != e1000_82541) && (hw->mac.type != e1000_82547))
		goto out;

	if (!(e1000_ttl_workaround_enabled_82541(hw)))
		goto out;

	/* Check for link first */
	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
	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;
			dsp_value = DSP_RESET_ENABLE;
		} else {
			ret_val = E1000_SUCCESS;
			goto out;
		}
	} else {
		if (dev_spec->dsp_reset_counter == 0) {
			/*
			 * Workaround not activated,
			 * check if it needs activation
			 */
			ret_val = hw->phy.ops.read_reg(hw,
			    PHY_AUTONEG_EXP,
			    &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) {
				dev_spec->dsp_reset_counter++;
			} else {
				ret_val = E1000_SUCCESS;
				goto out;
			}
		}

		/* After 5 times, stop the workaround */
		if (dev_spec->dsp_reset_counter > E1000_MAX_DSP_RESETS) {
			dev_spec->dsp_reset_counter = 0;
			dsp_value = DSP_RESET_ENABLE;
		} else {
			if (dev_spec->dsp_reset_counter) {
				dsp_value = (dev_spec->dsp_reset_counter & 1)
				    ? DSP_RESET_DISABLE
				    : DSP_RESET_ENABLE;
				dev_spec->dsp_reset_counter++;
			}
		}
	}

	ret_val =
	    hw->phy.ops.write_reg(hw, IGP01E1000_PHY_DSP_RESET, dsp_value);

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
e1000_power_down_phy_copper_82541(struct e1000_hw *hw)
{
	/* If the management interface is not enabled, then power down */
	if (!(E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_SMBUS_EN))
		e1000_power_down_phy_copper(hw);
}

/*
 * 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
e1000_clear_hw_cntrs_82541(struct e1000_hw *hw)
{
	DEBUGFUNC("e1000_clear_hw_cntrs_82541");

	e1000_clear_hw_cntrs_base_generic(hw);

	(void) E1000_READ_REG(hw, E1000_PRC64);
	(void) E1000_READ_REG(hw, E1000_PRC127);
	(void) E1000_READ_REG(hw, E1000_PRC255);
	(void) E1000_READ_REG(hw, E1000_PRC511);
	(void) E1000_READ_REG(hw, E1000_PRC1023);
	(void) E1000_READ_REG(hw, E1000_PRC1522);
	(void) E1000_READ_REG(hw, E1000_PTC64);
	(void) E1000_READ_REG(hw, E1000_PTC127);
	(void) E1000_READ_REG(hw, E1000_PTC255);
	(void) E1000_READ_REG(hw, E1000_PTC511);
	(void) E1000_READ_REG(hw, E1000_PTC1023);
	(void) E1000_READ_REG(hw, E1000_PTC1522);

	(void) E1000_READ_REG(hw, E1000_ALGNERRC);
	(void) E1000_READ_REG(hw, E1000_RXERRC);
	(void) E1000_READ_REG(hw, E1000_TNCRS);
	(void) E1000_READ_REG(hw, E1000_CEXTERR);
	(void) E1000_READ_REG(hw, E1000_TSCTC);
	(void) E1000_READ_REG(hw, E1000_TSCTFC);

	(void) E1000_READ_REG(hw, E1000_MGTPRC);
	(void) E1000_READ_REG(hw, E1000_MGTPDC);
	(void) E1000_READ_REG(hw, E1000_MGTPTC);
}