xref: /freebsd/sys/dev/e1000/e1000_82541.c (revision 71625ec9)
18cfa0ad2SJack F Vogel /******************************************************************************
27282444bSPedro F. Giffuni   SPDX-License-Identifier: BSD-3-Clause
38cfa0ad2SJack F Vogel 
4702cac6cSKevin Bowling   Copyright (c) 2001-2020, Intel Corporation
58cfa0ad2SJack F Vogel   All rights reserved.
68cfa0ad2SJack F Vogel 
78cfa0ad2SJack F Vogel   Redistribution and use in source and binary forms, with or without
88cfa0ad2SJack F Vogel   modification, are permitted provided that the following conditions are met:
98cfa0ad2SJack F Vogel 
108cfa0ad2SJack F Vogel    1. Redistributions of source code must retain the above copyright notice,
118cfa0ad2SJack F Vogel       this list of conditions and the following disclaimer.
128cfa0ad2SJack F Vogel 
138cfa0ad2SJack F Vogel    2. Redistributions in binary form must reproduce the above copyright
148cfa0ad2SJack F Vogel       notice, this list of conditions and the following disclaimer in the
158cfa0ad2SJack F Vogel       documentation and/or other materials provided with the distribution.
168cfa0ad2SJack F Vogel 
178cfa0ad2SJack F Vogel    3. Neither the name of the Intel Corporation nor the names of its
188cfa0ad2SJack F Vogel       contributors may be used to endorse or promote products derived from
198cfa0ad2SJack F Vogel       this software without specific prior written permission.
208cfa0ad2SJack F Vogel 
218cfa0ad2SJack F Vogel   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
228cfa0ad2SJack F Vogel   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
238cfa0ad2SJack F Vogel   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
248cfa0ad2SJack F Vogel   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
258cfa0ad2SJack F Vogel   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
268cfa0ad2SJack F Vogel   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
278cfa0ad2SJack F Vogel   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
288cfa0ad2SJack F Vogel   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
298cfa0ad2SJack F Vogel   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
308cfa0ad2SJack F Vogel   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
318cfa0ad2SJack F Vogel   POSSIBILITY OF SUCH DAMAGE.
328cfa0ad2SJack F Vogel 
338cfa0ad2SJack F Vogel ******************************************************************************/
348cfa0ad2SJack F Vogel 
35daf9197cSJack F Vogel /*
36daf9197cSJack F Vogel  * 82541EI Gigabit Ethernet Controller
37daf9197cSJack F Vogel  * 82541ER Gigabit Ethernet Controller
38daf9197cSJack F Vogel  * 82541GI Gigabit Ethernet Controller
39daf9197cSJack F Vogel  * 82541PI Gigabit Ethernet Controller
40daf9197cSJack F Vogel  * 82547EI Gigabit Ethernet Controller
41daf9197cSJack F Vogel  * 82547GI Gigabit Ethernet Controller
428cfa0ad2SJack F Vogel  */
438cfa0ad2SJack F Vogel 
448cfa0ad2SJack F Vogel #include "e1000_api.h"
458cfa0ad2SJack F Vogel 
468cfa0ad2SJack F Vogel static s32  e1000_init_phy_params_82541(struct e1000_hw *hw);
478cfa0ad2SJack F Vogel static s32  e1000_init_nvm_params_82541(struct e1000_hw *hw);
488cfa0ad2SJack F Vogel static s32  e1000_init_mac_params_82541(struct e1000_hw *hw);
498cfa0ad2SJack F Vogel static s32  e1000_reset_hw_82541(struct e1000_hw *hw);
508cfa0ad2SJack F Vogel static s32  e1000_init_hw_82541(struct e1000_hw *hw);
518cfa0ad2SJack F Vogel static s32  e1000_get_link_up_info_82541(struct e1000_hw *hw, u16 *speed,
528cfa0ad2SJack F Vogel 					 u16 *duplex);
538cfa0ad2SJack F Vogel static s32  e1000_phy_hw_reset_82541(struct e1000_hw *hw);
548cfa0ad2SJack F Vogel static s32  e1000_setup_copper_link_82541(struct e1000_hw *hw);
558cfa0ad2SJack F Vogel static s32  e1000_check_for_link_82541(struct e1000_hw *hw);
568cfa0ad2SJack F Vogel static s32  e1000_get_cable_length_igp_82541(struct e1000_hw *hw);
578cfa0ad2SJack F Vogel static s32  e1000_set_d3_lplu_state_82541(struct e1000_hw *hw,
588cfa0ad2SJack F Vogel 					  bool active);
598cfa0ad2SJack F Vogel static s32  e1000_setup_led_82541(struct e1000_hw *hw);
608cfa0ad2SJack F Vogel static s32  e1000_cleanup_led_82541(struct e1000_hw *hw);
618cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_82541(struct e1000_hw *hw);
624edd8523SJack F Vogel static s32  e1000_read_mac_addr_82541(struct e1000_hw *hw);
638cfa0ad2SJack F Vogel static s32  e1000_config_dsp_after_link_change_82541(struct e1000_hw *hw,
648cfa0ad2SJack F Vogel 						     bool link_up);
658cfa0ad2SJack F Vogel static s32  e1000_phy_init_script_82541(struct e1000_hw *hw);
668cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_82541(struct e1000_hw *hw);
678cfa0ad2SJack F Vogel 
6848600901SSean Bruno static const u16 e1000_igp_cable_length_table[] = {
6948600901SSean Bruno 	5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 10, 10, 10, 10, 10,
7048600901SSean Bruno 	10, 10, 20, 20, 20, 20, 20, 25, 25, 25, 25, 25, 25, 25, 30, 30, 30, 30,
7148600901SSean Bruno 	40, 40, 40, 40, 40, 40, 40, 40, 40, 50, 50, 50, 50, 50, 50, 50, 60, 60,
7248600901SSean Bruno 	60, 60, 60, 60, 60, 60, 60, 70, 70, 70, 70, 70, 70, 80, 80, 80, 80, 80,
7348600901SSean Bruno 	80, 90, 90, 90, 90, 90, 90, 90, 90, 90, 100, 100, 100, 100, 100, 100,
7448600901SSean Bruno 	100, 100, 100, 100, 100, 100, 100, 100, 110, 110, 110, 110, 110, 110,
7548600901SSean Bruno 	110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 120, 120,
7648600901SSean Bruno 	120, 120, 120, 120, 120, 120, 120, 120};
778cfa0ad2SJack F Vogel #define IGP01E1000_AGC_LENGTH_TABLE_SIZE \
788cfa0ad2SJack F Vogel 		(sizeof(e1000_igp_cable_length_table) / \
798cfa0ad2SJack F Vogel 		 sizeof(e1000_igp_cable_length_table[0]))
808cfa0ad2SJack F Vogel 
818cfa0ad2SJack F Vogel /**
828cfa0ad2SJack F Vogel  *  e1000_init_phy_params_82541 - Init PHY func ptrs.
838cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
848cfa0ad2SJack F Vogel  **/
e1000_init_phy_params_82541(struct e1000_hw * hw)858cfa0ad2SJack F Vogel static s32 e1000_init_phy_params_82541(struct e1000_hw *hw)
868cfa0ad2SJack F Vogel {
878cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
88c80429ceSEric Joyner 	s32 ret_val;
898cfa0ad2SJack F Vogel 
908cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_phy_params_82541");
918cfa0ad2SJack F Vogel 
928cfa0ad2SJack F Vogel 	phy->addr		= 1;
938cfa0ad2SJack F Vogel 	phy->autoneg_mask	= AUTONEG_ADVERTISE_SPEED_DEFAULT;
948cfa0ad2SJack F Vogel 	phy->reset_delay_us	= 10000;
958cfa0ad2SJack F Vogel 	phy->type		= e1000_phy_igp;
968cfa0ad2SJack F Vogel 
978cfa0ad2SJack F Vogel 	/* Function Pointers */
988cfa0ad2SJack F Vogel 	phy->ops.check_polarity	= e1000_check_polarity_igp;
998cfa0ad2SJack F Vogel 	phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp;
1008cfa0ad2SJack F Vogel 	phy->ops.get_cable_length = e1000_get_cable_length_igp_82541;
1018cfa0ad2SJack F Vogel 	phy->ops.get_cfg_done	= e1000_get_cfg_done_generic;
1028cfa0ad2SJack F Vogel 	phy->ops.get_info	= e1000_get_phy_info_igp;
1038cfa0ad2SJack F Vogel 	phy->ops.read_reg	= e1000_read_phy_reg_igp;
1048cfa0ad2SJack F Vogel 	phy->ops.reset		= e1000_phy_hw_reset_82541;
1058cfa0ad2SJack F Vogel 	phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_82541;
1068cfa0ad2SJack F Vogel 	phy->ops.write_reg	= e1000_write_phy_reg_igp;
1078cfa0ad2SJack F Vogel 	phy->ops.power_up	= e1000_power_up_phy_copper;
1088cfa0ad2SJack F Vogel 	phy->ops.power_down	= e1000_power_down_phy_copper_82541;
1098cfa0ad2SJack F Vogel 
1108cfa0ad2SJack F Vogel 	ret_val = e1000_get_phy_id(hw);
1118cfa0ad2SJack F Vogel 	if (ret_val)
1128cfa0ad2SJack F Vogel 		goto out;
1138cfa0ad2SJack F Vogel 
1148cfa0ad2SJack F Vogel 	/* Verify phy id */
1158cfa0ad2SJack F Vogel 	if (phy->id != IGP01E1000_I_PHY_ID) {
1168cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_PHY;
1178cfa0ad2SJack F Vogel 		goto out;
1188cfa0ad2SJack F Vogel 	}
1198cfa0ad2SJack F Vogel 
1208cfa0ad2SJack F Vogel out:
1218cfa0ad2SJack F Vogel 	return ret_val;
1228cfa0ad2SJack F Vogel }
1238cfa0ad2SJack F Vogel 
1248cfa0ad2SJack F Vogel /**
1258cfa0ad2SJack F Vogel  *  e1000_init_nvm_params_82541 - Init NVM func ptrs.
1268cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
1278cfa0ad2SJack F Vogel  **/
e1000_init_nvm_params_82541(struct e1000_hw * hw)1288cfa0ad2SJack F Vogel static s32 e1000_init_nvm_params_82541(struct e1000_hw *hw)
1298cfa0ad2SJack F Vogel {
1308cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
1318cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
1328cfa0ad2SJack F Vogel 	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
1338cfa0ad2SJack F Vogel 	u16 size;
1348cfa0ad2SJack F Vogel 
1358cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_nvm_params_82541");
1368cfa0ad2SJack F Vogel 
1378cfa0ad2SJack F Vogel 	switch (nvm->override) {
1388cfa0ad2SJack F Vogel 	case e1000_nvm_override_spi_large:
1398cfa0ad2SJack F Vogel 		nvm->type = e1000_nvm_eeprom_spi;
1408cfa0ad2SJack F Vogel 		eecd |= E1000_EECD_ADDR_BITS;
1418cfa0ad2SJack F Vogel 		break;
1428cfa0ad2SJack F Vogel 	case e1000_nvm_override_spi_small:
1438cfa0ad2SJack F Vogel 		nvm->type = e1000_nvm_eeprom_spi;
1448cfa0ad2SJack F Vogel 		eecd &= ~E1000_EECD_ADDR_BITS;
1458cfa0ad2SJack F Vogel 		break;
1468cfa0ad2SJack F Vogel 	case e1000_nvm_override_microwire_large:
1478cfa0ad2SJack F Vogel 		nvm->type = e1000_nvm_eeprom_microwire;
1488cfa0ad2SJack F Vogel 		eecd |= E1000_EECD_SIZE;
1498cfa0ad2SJack F Vogel 		break;
1508cfa0ad2SJack F Vogel 	case e1000_nvm_override_microwire_small:
1518cfa0ad2SJack F Vogel 		nvm->type = e1000_nvm_eeprom_microwire;
1528cfa0ad2SJack F Vogel 		eecd &= ~E1000_EECD_SIZE;
1538cfa0ad2SJack F Vogel 		break;
1548cfa0ad2SJack F Vogel 	default:
15548600901SSean Bruno 		nvm->type = eecd & E1000_EECD_TYPE ? e1000_nvm_eeprom_spi
1568cfa0ad2SJack F Vogel 			    : e1000_nvm_eeprom_microwire;
1578cfa0ad2SJack F Vogel 		break;
1588cfa0ad2SJack F Vogel 	}
1598cfa0ad2SJack F Vogel 
1608cfa0ad2SJack F Vogel 	if (nvm->type == e1000_nvm_eeprom_spi) {
16148600901SSean Bruno 		nvm->address_bits = (eecd & E1000_EECD_ADDR_BITS) ? 16 : 8;
1628cfa0ad2SJack F Vogel 		nvm->delay_usec = 1;
1638cfa0ad2SJack F Vogel 		nvm->opcode_bits = 8;
16448600901SSean Bruno 		nvm->page_size = (eecd & E1000_EECD_ADDR_BITS) ? 32 : 8;
1658cfa0ad2SJack F Vogel 
1668cfa0ad2SJack F Vogel 		/* Function Pointers */
1678cfa0ad2SJack F Vogel 		nvm->ops.acquire	= e1000_acquire_nvm_generic;
1688cfa0ad2SJack F Vogel 		nvm->ops.read		= e1000_read_nvm_spi;
1698cfa0ad2SJack F Vogel 		nvm->ops.release	= e1000_release_nvm_generic;
1708cfa0ad2SJack F Vogel 		nvm->ops.update		= e1000_update_nvm_checksum_generic;
1718cfa0ad2SJack F Vogel 		nvm->ops.valid_led_default = e1000_valid_led_default_generic;
1728cfa0ad2SJack F Vogel 		nvm->ops.validate	= e1000_validate_nvm_checksum_generic;
1738cfa0ad2SJack F Vogel 		nvm->ops.write		= e1000_write_nvm_spi;
1748cfa0ad2SJack F Vogel 
1758cfa0ad2SJack F Vogel 		/*
1768cfa0ad2SJack F Vogel 		 * nvm->word_size must be discovered after the pointers
1778cfa0ad2SJack F Vogel 		 * are set so we can verify the size from the nvm image
1788cfa0ad2SJack F Vogel 		 * itself.  Temporarily set it to a dummy value so the
1798cfa0ad2SJack F Vogel 		 * read will work.
1808cfa0ad2SJack F Vogel 		 */
1818cfa0ad2SJack F Vogel 		nvm->word_size = 64;
1828cfa0ad2SJack F Vogel 		ret_val = nvm->ops.read(hw, NVM_CFG, 1, &size);
1838cfa0ad2SJack F Vogel 		if (ret_val)
1848cfa0ad2SJack F Vogel 			goto out;
1858cfa0ad2SJack F Vogel 		size = (size & NVM_SIZE_MASK) >> NVM_SIZE_SHIFT;
1868cfa0ad2SJack F Vogel 		/*
1878cfa0ad2SJack F Vogel 		 * if size != 0, it can be added to a constant and become
1888cfa0ad2SJack F Vogel 		 * the left-shift value to set the word_size.  Otherwise,
1898cfa0ad2SJack F Vogel 		 * word_size stays at 64.
1908cfa0ad2SJack F Vogel 		 */
1918cfa0ad2SJack F Vogel 		if (size) {
1928cfa0ad2SJack F Vogel 			size += NVM_WORD_SIZE_BASE_SHIFT_82541;
1938cfa0ad2SJack F Vogel 			nvm->word_size = 1 << size;
1948cfa0ad2SJack F Vogel 		}
1958cfa0ad2SJack F Vogel 	} else {
19648600901SSean Bruno 		nvm->address_bits = (eecd & E1000_EECD_ADDR_BITS) ? 8 : 6;
1978cfa0ad2SJack F Vogel 		nvm->delay_usec = 50;
1988cfa0ad2SJack F Vogel 		nvm->opcode_bits = 3;
19948600901SSean Bruno 		nvm->word_size = (eecd & E1000_EECD_ADDR_BITS) ? 256 : 64;
2008cfa0ad2SJack F Vogel 
2018cfa0ad2SJack F Vogel 		/* Function Pointers */
2028cfa0ad2SJack F Vogel 		nvm->ops.acquire	= e1000_acquire_nvm_generic;
2038cfa0ad2SJack F Vogel 		nvm->ops.read		= e1000_read_nvm_microwire;
2048cfa0ad2SJack F Vogel 		nvm->ops.release	= e1000_release_nvm_generic;
2058cfa0ad2SJack F Vogel 		nvm->ops.update		= e1000_update_nvm_checksum_generic;
2068cfa0ad2SJack F Vogel 		nvm->ops.valid_led_default = e1000_valid_led_default_generic;
2078cfa0ad2SJack F Vogel 		nvm->ops.validate	= e1000_validate_nvm_checksum_generic;
2088cfa0ad2SJack F Vogel 		nvm->ops.write		= e1000_write_nvm_microwire;
2098cfa0ad2SJack F Vogel 	}
2108cfa0ad2SJack F Vogel 
2118cfa0ad2SJack F Vogel out:
2128cfa0ad2SJack F Vogel 	return ret_val;
2138cfa0ad2SJack F Vogel }
2148cfa0ad2SJack F Vogel 
2158cfa0ad2SJack F Vogel /**
2168cfa0ad2SJack F Vogel  *  e1000_init_mac_params_82541 - Init MAC func ptrs.
2178cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
2188cfa0ad2SJack F Vogel  **/
e1000_init_mac_params_82541(struct e1000_hw * hw)2198cfa0ad2SJack F Vogel static s32 e1000_init_mac_params_82541(struct e1000_hw *hw)
2208cfa0ad2SJack F Vogel {
2218cfa0ad2SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
2228cfa0ad2SJack F Vogel 
2238cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_mac_params_82541");
2248cfa0ad2SJack F Vogel 
2258cfa0ad2SJack F Vogel 	/* Set media type */
2268cfa0ad2SJack F Vogel 	hw->phy.media_type = e1000_media_type_copper;
2278cfa0ad2SJack F Vogel 	/* Set mta register count */
2288cfa0ad2SJack F Vogel 	mac->mta_reg_count = 128;
2298cfa0ad2SJack F Vogel 	/* Set rar entry count */
2308cfa0ad2SJack F Vogel 	mac->rar_entry_count = E1000_RAR_ENTRIES;
2318cfa0ad2SJack F Vogel 	/* Set if part includes ASF firmware */
2321bbdc25fSKevin Bowling 	mac->asf_firmware_present = true;
2338cfa0ad2SJack F Vogel 
2348cfa0ad2SJack F Vogel 	/* Function Pointers */
2358cfa0ad2SJack F Vogel 
2368cfa0ad2SJack F Vogel 	/* bus type/speed/width */
2378cfa0ad2SJack F Vogel 	mac->ops.get_bus_info = e1000_get_bus_info_pci_generic;
238daf9197cSJack F Vogel 	/* function id */
239daf9197cSJack F Vogel 	mac->ops.set_lan_id = e1000_set_lan_id_single_port;
2408cfa0ad2SJack F Vogel 	/* reset */
2418cfa0ad2SJack F Vogel 	mac->ops.reset_hw = e1000_reset_hw_82541;
2428cfa0ad2SJack F Vogel 	/* hw initialization */
2438cfa0ad2SJack F Vogel 	mac->ops.init_hw = e1000_init_hw_82541;
2448cfa0ad2SJack F Vogel 	/* link setup */
2458cfa0ad2SJack F Vogel 	mac->ops.setup_link = e1000_setup_link_generic;
2468cfa0ad2SJack F Vogel 	/* physical interface link setup */
2478cfa0ad2SJack F Vogel 	mac->ops.setup_physical_interface = e1000_setup_copper_link_82541;
2488cfa0ad2SJack F Vogel 	/* check for link */
2498cfa0ad2SJack F Vogel 	mac->ops.check_for_link = e1000_check_for_link_82541;
2508cfa0ad2SJack F Vogel 	/* link info */
2518cfa0ad2SJack F Vogel 	mac->ops.get_link_up_info = e1000_get_link_up_info_82541;
2528cfa0ad2SJack F Vogel 	/* multicast address update */
2538cfa0ad2SJack F Vogel 	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
2548cfa0ad2SJack F Vogel 	/* writing VFTA */
2558cfa0ad2SJack F Vogel 	mac->ops.write_vfta = e1000_write_vfta_generic;
2568cfa0ad2SJack F Vogel 	/* clearing VFTA */
2578cfa0ad2SJack F Vogel 	mac->ops.clear_vfta = e1000_clear_vfta_generic;
2584edd8523SJack F Vogel 	/* read mac address */
2594edd8523SJack F Vogel 	mac->ops.read_mac_addr = e1000_read_mac_addr_82541;
260d035aa2dSJack F Vogel 	/* ID LED init */
261d035aa2dSJack F Vogel 	mac->ops.id_led_init = e1000_id_led_init_generic;
2628cfa0ad2SJack F Vogel 	/* setup LED */
2638cfa0ad2SJack F Vogel 	mac->ops.setup_led = e1000_setup_led_82541;
2648cfa0ad2SJack F Vogel 	/* cleanup LED */
2658cfa0ad2SJack F Vogel 	mac->ops.cleanup_led = e1000_cleanup_led_82541;
2668cfa0ad2SJack F Vogel 	/* turn on/off LED */
2678cfa0ad2SJack F Vogel 	mac->ops.led_on = e1000_led_on_generic;
2688cfa0ad2SJack F Vogel 	mac->ops.led_off = e1000_led_off_generic;
2698cfa0ad2SJack F Vogel 	/* clear hardware counters */
2708cfa0ad2SJack F Vogel 	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82541;
2718cfa0ad2SJack F Vogel 
272daf9197cSJack F Vogel 	return E1000_SUCCESS;
2738cfa0ad2SJack F Vogel }
2748cfa0ad2SJack F Vogel 
2758cfa0ad2SJack F Vogel /**
2768cfa0ad2SJack F Vogel  *  e1000_init_function_pointers_82541 - Init func ptrs.
2778cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
2788cfa0ad2SJack F Vogel  *
279daf9197cSJack F Vogel  *  Called to initialize all function pointers and parameters.
2808cfa0ad2SJack F Vogel  **/
e1000_init_function_pointers_82541(struct e1000_hw * hw)2818cfa0ad2SJack F Vogel void e1000_init_function_pointers_82541(struct e1000_hw *hw)
2828cfa0ad2SJack F Vogel {
2838cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_function_pointers_82541");
2848cfa0ad2SJack F Vogel 
2858cfa0ad2SJack F Vogel 	hw->mac.ops.init_params = e1000_init_mac_params_82541;
2868cfa0ad2SJack F Vogel 	hw->nvm.ops.init_params = e1000_init_nvm_params_82541;
2878cfa0ad2SJack F Vogel 	hw->phy.ops.init_params = e1000_init_phy_params_82541;
2888cfa0ad2SJack F Vogel }
2898cfa0ad2SJack F Vogel 
2908cfa0ad2SJack F Vogel /**
2918cfa0ad2SJack F Vogel  *  e1000_reset_hw_82541 - Reset hardware
2928cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
2938cfa0ad2SJack F Vogel  *
294daf9197cSJack F Vogel  *  This resets the hardware into a known state.
2958cfa0ad2SJack F Vogel  **/
e1000_reset_hw_82541(struct e1000_hw * hw)2968cfa0ad2SJack F Vogel static s32 e1000_reset_hw_82541(struct e1000_hw *hw)
2978cfa0ad2SJack F Vogel {
298c80429ceSEric Joyner 	u32 ledctl, ctrl, manc;
2998cfa0ad2SJack F Vogel 
3008cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_reset_hw_82541");
3018cfa0ad2SJack F Vogel 
3028cfa0ad2SJack F Vogel 	DEBUGOUT("Masking off all interrupts\n");
3038cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF);
3048cfa0ad2SJack F Vogel 
3058cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_RCTL, 0);
3068cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
3078cfa0ad2SJack F Vogel 	E1000_WRITE_FLUSH(hw);
3088cfa0ad2SJack F Vogel 
3098cfa0ad2SJack F Vogel 	/*
3108cfa0ad2SJack F Vogel 	 * Delay to allow any outstanding PCI transactions to complete
3118cfa0ad2SJack F Vogel 	 * before resetting the device.
3128cfa0ad2SJack F Vogel 	 */
3138cfa0ad2SJack F Vogel 	msec_delay(10);
3148cfa0ad2SJack F Vogel 
3158cfa0ad2SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
3168cfa0ad2SJack F Vogel 
3178cfa0ad2SJack F Vogel 	/* Must reset the Phy before resetting the MAC */
3188cfa0ad2SJack F Vogel 	if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {
3198cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_PHY_RST));
320c80429ceSEric Joyner 		E1000_WRITE_FLUSH(hw);
3218cfa0ad2SJack F Vogel 		msec_delay(5);
3228cfa0ad2SJack F Vogel 	}
3238cfa0ad2SJack F Vogel 
3248cfa0ad2SJack F Vogel 	DEBUGOUT("Issuing a global reset to 82541/82547 MAC\n");
3258cfa0ad2SJack F Vogel 	switch (hw->mac.type) {
3268cfa0ad2SJack F Vogel 	case e1000_82541:
3278cfa0ad2SJack F Vogel 	case e1000_82541_rev_2:
3288cfa0ad2SJack F Vogel 		/*
3298cfa0ad2SJack F Vogel 		 * These controllers can't ack the 64-bit write when
3308cfa0ad2SJack F Vogel 		 * issuing the reset, so we use IO-mapping as a
3318cfa0ad2SJack F Vogel 		 * workaround to issue the reset.
3328cfa0ad2SJack F Vogel 		 */
3338cfa0ad2SJack F Vogel 		E1000_WRITE_REG_IO(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
3348cfa0ad2SJack F Vogel 		break;
3358cfa0ad2SJack F Vogel 	default:
3368cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
3378cfa0ad2SJack F Vogel 		break;
3388cfa0ad2SJack F Vogel 	}
3398cfa0ad2SJack F Vogel 
3408cfa0ad2SJack F Vogel 	/* Wait for NVM reload */
3418cfa0ad2SJack F Vogel 	msec_delay(20);
3428cfa0ad2SJack F Vogel 
3438cfa0ad2SJack F Vogel 	/* Disable HW ARPs on ASF enabled adapters */
3448cfa0ad2SJack F Vogel 	manc = E1000_READ_REG(hw, E1000_MANC);
3458cfa0ad2SJack F Vogel 	manc &= ~E1000_MANC_ARP_EN;
3468cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_MANC, manc);
3478cfa0ad2SJack F Vogel 
3488cfa0ad2SJack F Vogel 	if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {
3498cfa0ad2SJack F Vogel 		e1000_phy_init_script_82541(hw);
3508cfa0ad2SJack F Vogel 
3518cfa0ad2SJack F Vogel 		/* Configure activity LED after Phy reset */
3528cfa0ad2SJack F Vogel 		ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
3538cfa0ad2SJack F Vogel 		ledctl &= IGP_ACTIVITY_LED_MASK;
3548cfa0ad2SJack F Vogel 		ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
3558cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
3568cfa0ad2SJack F Vogel 	}
3578cfa0ad2SJack F Vogel 
3588cfa0ad2SJack F Vogel 	/* Once again, mask the interrupts */
3598cfa0ad2SJack F Vogel 	DEBUGOUT("Masking off all interrupts\n");
3608cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF);
3618cfa0ad2SJack F Vogel 
3628cfa0ad2SJack F Vogel 	/* Clear any pending interrupt events. */
363c80429ceSEric Joyner 	E1000_READ_REG(hw, E1000_ICR);
3648cfa0ad2SJack F Vogel 
3658cfa0ad2SJack F Vogel 	return E1000_SUCCESS;
3668cfa0ad2SJack F Vogel }
3678cfa0ad2SJack F Vogel 
3688cfa0ad2SJack F Vogel /**
3698cfa0ad2SJack F Vogel  *  e1000_init_hw_82541 - Initialize hardware
3708cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
3718cfa0ad2SJack F Vogel  *
372daf9197cSJack F Vogel  *  This inits the hardware readying it for operation.
3738cfa0ad2SJack F Vogel  **/
e1000_init_hw_82541(struct e1000_hw * hw)3748cfa0ad2SJack F Vogel static s32 e1000_init_hw_82541(struct e1000_hw *hw)
3758cfa0ad2SJack F Vogel {
3768cfa0ad2SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
3779d81738fSJack F Vogel 	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
3788cfa0ad2SJack F Vogel 	u32 i, txdctl;
3798cfa0ad2SJack F Vogel 	s32 ret_val;
3808cfa0ad2SJack F Vogel 
3818cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_hw_82541");
3828cfa0ad2SJack F Vogel 
3838cfa0ad2SJack F Vogel 	/* Initialize identification LED */
384d035aa2dSJack F Vogel 	ret_val = mac->ops.id_led_init(hw);
3858cfa0ad2SJack F Vogel 	if (ret_val) {
3868cfa0ad2SJack F Vogel 		DEBUGOUT("Error initializing identification LED\n");
3878cfa0ad2SJack F Vogel 		/* This is not fatal and we should not stop init due to this */
3888cfa0ad2SJack F Vogel 	}
3898cfa0ad2SJack F Vogel 
3909d81738fSJack F Vogel 	/* Storing the Speed Power Down  value for later use */
39148600901SSean Bruno 	ret_val = hw->phy.ops.read_reg(hw, IGP01E1000_GMII_FIFO,
3929d81738fSJack F Vogel 				       &dev_spec->spd_default);
3939d81738fSJack F Vogel 	if (ret_val)
3949d81738fSJack F Vogel 		goto out;
3959d81738fSJack F Vogel 
3968cfa0ad2SJack F Vogel 	/* Disabling VLAN filtering */
3978cfa0ad2SJack F Vogel 	DEBUGOUT("Initializing the IEEE VLAN\n");
3988cfa0ad2SJack F Vogel 	mac->ops.clear_vfta(hw);
3998cfa0ad2SJack F Vogel 
4008cfa0ad2SJack F Vogel 	/* Setup the receive address. */
4018cfa0ad2SJack F Vogel 	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
4028cfa0ad2SJack F Vogel 
4038cfa0ad2SJack F Vogel 	/* Zero out the Multicast HASH table */
4048cfa0ad2SJack F Vogel 	DEBUGOUT("Zeroing the MTA\n");
4058cfa0ad2SJack F Vogel 	for (i = 0; i < mac->mta_reg_count; i++) {
4068cfa0ad2SJack F Vogel 		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
4078cfa0ad2SJack F Vogel 		/*
4088cfa0ad2SJack F Vogel 		 * Avoid back to back register writes by adding the register
4098cfa0ad2SJack F Vogel 		 * read (flush).  This is to protect against some strange
4108cfa0ad2SJack F Vogel 		 * bridge configurations that may issue Memory Write Block
4118cfa0ad2SJack F Vogel 		 * (MWB) to our register space.
4128cfa0ad2SJack F Vogel 		 */
4138cfa0ad2SJack F Vogel 		E1000_WRITE_FLUSH(hw);
4148cfa0ad2SJack F Vogel 	}
4158cfa0ad2SJack F Vogel 
4168cfa0ad2SJack F Vogel 	/* Setup link and flow control */
4178cfa0ad2SJack F Vogel 	ret_val = mac->ops.setup_link(hw);
4188cfa0ad2SJack F Vogel 
4198cfa0ad2SJack F Vogel 	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
4208cfa0ad2SJack F Vogel 	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
4218cfa0ad2SJack F Vogel 		  E1000_TXDCTL_FULL_TX_DESC_WB;
4228cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);
4238cfa0ad2SJack F Vogel 
4248cfa0ad2SJack F Vogel 	/*
4258cfa0ad2SJack F Vogel 	 * Clear all of the statistics registers (clear on read).  It is
4268cfa0ad2SJack F Vogel 	 * important that we do this after we have tried to establish link
4278cfa0ad2SJack F Vogel 	 * because the symbol error count will increment wildly if there
4288cfa0ad2SJack F Vogel 	 * is no link.
4298cfa0ad2SJack F Vogel 	 */
4308cfa0ad2SJack F Vogel 	e1000_clear_hw_cntrs_82541(hw);
4318cfa0ad2SJack F Vogel 
4329d81738fSJack F Vogel out:
4338cfa0ad2SJack F Vogel 	return ret_val;
4348cfa0ad2SJack F Vogel }
4358cfa0ad2SJack F Vogel 
4368cfa0ad2SJack F Vogel /**
4378cfa0ad2SJack F Vogel  * e1000_get_link_up_info_82541 - Report speed and duplex
4388cfa0ad2SJack F Vogel  * @hw: pointer to the HW structure
4398cfa0ad2SJack F Vogel  * @speed: pointer to speed buffer
4408cfa0ad2SJack F Vogel  * @duplex: pointer to duplex buffer
4418cfa0ad2SJack F Vogel  *
4428cfa0ad2SJack F Vogel  * Retrieve the current speed and duplex configuration.
4438cfa0ad2SJack F Vogel  **/
e1000_get_link_up_info_82541(struct e1000_hw * hw,u16 * speed,u16 * duplex)4448cfa0ad2SJack F Vogel static s32 e1000_get_link_up_info_82541(struct e1000_hw *hw, u16 *speed,
4458cfa0ad2SJack F Vogel 					u16 *duplex)
4468cfa0ad2SJack F Vogel {
4478cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
4488cfa0ad2SJack F Vogel 	s32 ret_val;
4498cfa0ad2SJack F Vogel 	u16 data;
4508cfa0ad2SJack F Vogel 
4518cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_get_link_up_info_82541");
4528cfa0ad2SJack F Vogel 
4538cfa0ad2SJack F Vogel 	ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex);
4548cfa0ad2SJack F Vogel 	if (ret_val)
4558cfa0ad2SJack F Vogel 		goto out;
4568cfa0ad2SJack F Vogel 
4578cfa0ad2SJack F Vogel 	if (!phy->speed_downgraded)
4588cfa0ad2SJack F Vogel 		goto out;
4598cfa0ad2SJack F Vogel 
4608cfa0ad2SJack F Vogel 	/*
4618cfa0ad2SJack F Vogel 	 * IGP01 PHY may advertise full duplex operation after speed
4628cfa0ad2SJack F Vogel 	 * downgrade even if it is operating at half duplex.
4638cfa0ad2SJack F Vogel 	 * Here we set the duplex settings to match the duplex in the
4648cfa0ad2SJack F Vogel 	 * link partner's capabilities.
4658cfa0ad2SJack F Vogel 	 */
4668cfa0ad2SJack F Vogel 	ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_EXP, &data);
4678cfa0ad2SJack F Vogel 	if (ret_val)
4688cfa0ad2SJack F Vogel 		goto out;
4698cfa0ad2SJack F Vogel 
4708cfa0ad2SJack F Vogel 	if (!(data & NWAY_ER_LP_NWAY_CAPS)) {
4718cfa0ad2SJack F Vogel 		*duplex = HALF_DUPLEX;
4728cfa0ad2SJack F Vogel 	} else {
4738cfa0ad2SJack F Vogel 		ret_val = phy->ops.read_reg(hw, PHY_LP_ABILITY, &data);
4748cfa0ad2SJack F Vogel 		if (ret_val)
4758cfa0ad2SJack F Vogel 			goto out;
4768cfa0ad2SJack F Vogel 
4778cfa0ad2SJack F Vogel 		if (*speed == SPEED_100) {
4788cfa0ad2SJack F Vogel 			if (!(data & NWAY_LPAR_100TX_FD_CAPS))
4798cfa0ad2SJack F Vogel 				*duplex = HALF_DUPLEX;
4808cfa0ad2SJack F Vogel 		} else if (*speed == SPEED_10) {
4818cfa0ad2SJack F Vogel 			if (!(data & NWAY_LPAR_10T_FD_CAPS))
4828cfa0ad2SJack F Vogel 				*duplex = HALF_DUPLEX;
4838cfa0ad2SJack F Vogel 		}
4848cfa0ad2SJack F Vogel 	}
4858cfa0ad2SJack F Vogel 
4868cfa0ad2SJack F Vogel out:
4878cfa0ad2SJack F Vogel 	return ret_val;
4888cfa0ad2SJack F Vogel }
4898cfa0ad2SJack F Vogel 
4908cfa0ad2SJack F Vogel /**
4918cfa0ad2SJack F Vogel  *  e1000_phy_hw_reset_82541 - PHY hardware reset
4928cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
4938cfa0ad2SJack F Vogel  *
4948cfa0ad2SJack F Vogel  *  Verify the reset block is not blocking us from resetting.  Acquire
4958cfa0ad2SJack F Vogel  *  semaphore (if necessary) and read/set/write the device control reset
4968cfa0ad2SJack F Vogel  *  bit in the PHY.  Wait the appropriate delay time for the device to
4978cfa0ad2SJack F Vogel  *  reset and release the semaphore (if necessary).
4988cfa0ad2SJack F Vogel  **/
e1000_phy_hw_reset_82541(struct e1000_hw * hw)4998cfa0ad2SJack F Vogel static s32 e1000_phy_hw_reset_82541(struct e1000_hw *hw)
5008cfa0ad2SJack F Vogel {
5018cfa0ad2SJack F Vogel 	s32 ret_val;
5028cfa0ad2SJack F Vogel 	u32 ledctl;
5038cfa0ad2SJack F Vogel 
5048cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_phy_hw_reset_82541");
5058cfa0ad2SJack F Vogel 
5068cfa0ad2SJack F Vogel 	ret_val = e1000_phy_hw_reset_generic(hw);
5078cfa0ad2SJack F Vogel 	if (ret_val)
5088cfa0ad2SJack F Vogel 		goto out;
5098cfa0ad2SJack F Vogel 
5108cfa0ad2SJack F Vogel 	e1000_phy_init_script_82541(hw);
5118cfa0ad2SJack F Vogel 
5128cfa0ad2SJack F Vogel 	if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {
5138cfa0ad2SJack F Vogel 		/* Configure activity LED after PHY reset */
5148cfa0ad2SJack F Vogel 		ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
5158cfa0ad2SJack F Vogel 		ledctl &= IGP_ACTIVITY_LED_MASK;
5168cfa0ad2SJack F Vogel 		ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
5178cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
5188cfa0ad2SJack F Vogel 	}
5198cfa0ad2SJack F Vogel 
5208cfa0ad2SJack F Vogel out:
5218cfa0ad2SJack F Vogel 	return ret_val;
5228cfa0ad2SJack F Vogel }
5238cfa0ad2SJack F Vogel 
5248cfa0ad2SJack F Vogel /**
5258cfa0ad2SJack F Vogel  *  e1000_setup_copper_link_82541 - Configure copper link settings
5268cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
5278cfa0ad2SJack F Vogel  *
5288cfa0ad2SJack F Vogel  *  Calls the appropriate function to configure the link for auto-neg or forced
5298cfa0ad2SJack F Vogel  *  speed and duplex.  Then we check for link, once link is established calls
5308cfa0ad2SJack F Vogel  *  to configure collision distance and flow control are called.  If link is
531daf9197cSJack F Vogel  *  not established, we return -E1000_ERR_PHY (-2).
5328cfa0ad2SJack F Vogel  **/
e1000_setup_copper_link_82541(struct e1000_hw * hw)5338cfa0ad2SJack F Vogel static s32 e1000_setup_copper_link_82541(struct e1000_hw *hw)
5348cfa0ad2SJack F Vogel {
5358cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
536daf9197cSJack F Vogel 	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
5378cfa0ad2SJack F Vogel 	s32  ret_val;
5388cfa0ad2SJack F Vogel 	u32 ctrl, ledctl;
5398cfa0ad2SJack F Vogel 
5408cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_setup_copper_link_82541");
5418cfa0ad2SJack F Vogel 
5428cfa0ad2SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
5438cfa0ad2SJack F Vogel 	ctrl |= E1000_CTRL_SLU;
5448cfa0ad2SJack F Vogel 	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
5458cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
5468cfa0ad2SJack F Vogel 
54748600901SSean Bruno 
5488cfa0ad2SJack F Vogel 	/* Earlier revs of the IGP phy require us to force MDI. */
5498cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_82541 || hw->mac.type == e1000_82547) {
5508cfa0ad2SJack F Vogel 		dev_spec->dsp_config = e1000_dsp_config_disabled;
5518cfa0ad2SJack F Vogel 		phy->mdix = 1;
5528cfa0ad2SJack F Vogel 	} else {
5538cfa0ad2SJack F Vogel 		dev_spec->dsp_config = e1000_dsp_config_enabled;
5548cfa0ad2SJack F Vogel 	}
5558cfa0ad2SJack F Vogel 
5568cfa0ad2SJack F Vogel 	ret_val = e1000_copper_link_setup_igp(hw);
5578cfa0ad2SJack F Vogel 	if (ret_val)
5588cfa0ad2SJack F Vogel 		goto out;
5598cfa0ad2SJack F Vogel 
5608cfa0ad2SJack F Vogel 	if (hw->mac.autoneg) {
5618cfa0ad2SJack F Vogel 		if (dev_spec->ffe_config == e1000_ffe_config_active)
5628cfa0ad2SJack F Vogel 			dev_spec->ffe_config = e1000_ffe_config_enabled;
5638cfa0ad2SJack F Vogel 	}
5648cfa0ad2SJack F Vogel 
5658cfa0ad2SJack F Vogel 	/* Configure activity LED after Phy reset */
5668cfa0ad2SJack F Vogel 	ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
5678cfa0ad2SJack F Vogel 	ledctl &= IGP_ACTIVITY_LED_MASK;
5688cfa0ad2SJack F Vogel 	ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
5698cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
5708cfa0ad2SJack F Vogel 
5718cfa0ad2SJack F Vogel 	ret_val = e1000_setup_copper_link_generic(hw);
5728cfa0ad2SJack F Vogel 
5738cfa0ad2SJack F Vogel out:
5748cfa0ad2SJack F Vogel 	return ret_val;
5758cfa0ad2SJack F Vogel }
5768cfa0ad2SJack F Vogel 
5778cfa0ad2SJack F Vogel /**
5788cfa0ad2SJack F Vogel  *  e1000_check_for_link_82541 - Check/Store link connection
5798cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
5808cfa0ad2SJack F Vogel  *
5818cfa0ad2SJack F Vogel  *  This checks the link condition of the adapter and stores the
582daf9197cSJack F Vogel  *  results in the hw->mac structure.
5838cfa0ad2SJack F Vogel  **/
e1000_check_for_link_82541(struct e1000_hw * hw)5848cfa0ad2SJack F Vogel static s32 e1000_check_for_link_82541(struct e1000_hw *hw)
5858cfa0ad2SJack F Vogel {
5868cfa0ad2SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
5878cfa0ad2SJack F Vogel 	s32 ret_val;
5888cfa0ad2SJack F Vogel 	bool link;
5898cfa0ad2SJack F Vogel 
5908cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_check_for_link_82541");
5918cfa0ad2SJack F Vogel 
5928cfa0ad2SJack F Vogel 	/*
5938cfa0ad2SJack F Vogel 	 * We only want to go out to the PHY registers to see if Auto-Neg
5948cfa0ad2SJack F Vogel 	 * has completed and/or if our link status has changed.  The
5958cfa0ad2SJack F Vogel 	 * get_link_status flag is set upon receiving a Link Status
5968cfa0ad2SJack F Vogel 	 * Change or Rx Sequence Error interrupt.
5978cfa0ad2SJack F Vogel 	 */
5988cfa0ad2SJack F Vogel 	if (!mac->get_link_status) {
5998cfa0ad2SJack F Vogel 		ret_val = E1000_SUCCESS;
6008cfa0ad2SJack F Vogel 		goto out;
6018cfa0ad2SJack F Vogel 	}
6028cfa0ad2SJack F Vogel 
6038cfa0ad2SJack F Vogel 	/*
6048cfa0ad2SJack F Vogel 	 * First we want to see if the MII Status Register reports
6058cfa0ad2SJack F Vogel 	 * link.  If so, then we want to get the current speed/duplex
6068cfa0ad2SJack F Vogel 	 * of the PHY.
6078cfa0ad2SJack F Vogel 	 */
6088cfa0ad2SJack F Vogel 	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
6098cfa0ad2SJack F Vogel 	if (ret_val)
6108cfa0ad2SJack F Vogel 		goto out;
6118cfa0ad2SJack F Vogel 
6128cfa0ad2SJack F Vogel 	if (!link) {
6131bbdc25fSKevin Bowling 		ret_val = e1000_config_dsp_after_link_change_82541(hw, false);
6148cfa0ad2SJack F Vogel 		goto out; /* No link detected */
6158cfa0ad2SJack F Vogel 	}
6168cfa0ad2SJack F Vogel 
6171bbdc25fSKevin Bowling 	mac->get_link_status = false;
6188cfa0ad2SJack F Vogel 
6198cfa0ad2SJack F Vogel 	/*
6208cfa0ad2SJack F Vogel 	 * Check if there was DownShift, must be checked
6218cfa0ad2SJack F Vogel 	 * immediately after link-up
6228cfa0ad2SJack F Vogel 	 */
6238cfa0ad2SJack F Vogel 	e1000_check_downshift_generic(hw);
6248cfa0ad2SJack F Vogel 
6258cfa0ad2SJack F Vogel 	/*
6268cfa0ad2SJack F Vogel 	 * If we are forcing speed/duplex, then we simply return since
6278cfa0ad2SJack F Vogel 	 * we have already determined whether we have link or not.
6288cfa0ad2SJack F Vogel 	 */
6298cfa0ad2SJack F Vogel 	if (!mac->autoneg) {
6308cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_CONFIG;
6318cfa0ad2SJack F Vogel 		goto out;
6328cfa0ad2SJack F Vogel 	}
6338cfa0ad2SJack F Vogel 
6341bbdc25fSKevin Bowling 	ret_val = e1000_config_dsp_after_link_change_82541(hw, true);
6358cfa0ad2SJack F Vogel 
6368cfa0ad2SJack F Vogel 	/*
6378cfa0ad2SJack F Vogel 	 * Auto-Neg is enabled.  Auto Speed Detection takes care
6388cfa0ad2SJack F Vogel 	 * of MAC speed/duplex configuration.  So we only need to
6398cfa0ad2SJack F Vogel 	 * configure Collision Distance in the MAC.
6408cfa0ad2SJack F Vogel 	 */
641ab5d0362SJack F Vogel 	mac->ops.config_collision_dist(hw);
6428cfa0ad2SJack F Vogel 
6438cfa0ad2SJack F Vogel 	/*
6448cfa0ad2SJack F Vogel 	 * Configure Flow Control now that Auto-Neg has completed.
6458cfa0ad2SJack F Vogel 	 * First, we need to restore the desired flow control
6468cfa0ad2SJack F Vogel 	 * settings because we may have had to re-autoneg with a
6478cfa0ad2SJack F Vogel 	 * different link partner.
6488cfa0ad2SJack F Vogel 	 */
6498cfa0ad2SJack F Vogel 	ret_val = e1000_config_fc_after_link_up_generic(hw);
65048600901SSean Bruno 	if (ret_val)
6518cfa0ad2SJack F Vogel 		DEBUGOUT("Error configuring flow control\n");
6528cfa0ad2SJack F Vogel 
6538cfa0ad2SJack F Vogel out:
6548cfa0ad2SJack F Vogel 	return ret_val;
6558cfa0ad2SJack F Vogel }
6568cfa0ad2SJack F Vogel 
6578cfa0ad2SJack F Vogel /**
6588cfa0ad2SJack F Vogel  *  e1000_config_dsp_after_link_change_82541 - Config DSP after link
6598cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
6608cfa0ad2SJack F Vogel  *  @link_up: boolean flag for link up status
6618cfa0ad2SJack F Vogel  *
6628cfa0ad2SJack F Vogel  *  Return E1000_ERR_PHY when failing to read/write the PHY, else E1000_SUCCESS
6638cfa0ad2SJack F Vogel  *  at any other case.
6648cfa0ad2SJack F Vogel  *
6658cfa0ad2SJack F Vogel  *  82541_rev_2 & 82547_rev_2 have the capability to configure the DSP when a
6668cfa0ad2SJack F Vogel  *  gigabit link is achieved to improve link quality.
6678cfa0ad2SJack F Vogel  **/
e1000_config_dsp_after_link_change_82541(struct e1000_hw * hw,bool link_up)6688cfa0ad2SJack F Vogel static s32 e1000_config_dsp_after_link_change_82541(struct e1000_hw *hw,
6698cfa0ad2SJack F Vogel 						    bool link_up)
6708cfa0ad2SJack F Vogel {
6718cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
672daf9197cSJack F Vogel 	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
6738cfa0ad2SJack F Vogel 	s32 ret_val;
6748cfa0ad2SJack F Vogel 	u32 idle_errs = 0;
6758cfa0ad2SJack F Vogel 	u16 phy_data, phy_saved_data, speed, duplex, i;
6768cfa0ad2SJack F Vogel 	u16 ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_20;
67748600901SSean Bruno 	u16 dsp_reg_array[IGP01E1000_PHY_CHANNEL_NUM] = {
67848600901SSean Bruno 						IGP01E1000_PHY_AGC_PARAM_A,
6798cfa0ad2SJack F Vogel 						IGP01E1000_PHY_AGC_PARAM_B,
6808cfa0ad2SJack F Vogel 						IGP01E1000_PHY_AGC_PARAM_C,
6818cfa0ad2SJack F Vogel 						IGP01E1000_PHY_AGC_PARAM_D};
6828cfa0ad2SJack F Vogel 
6838cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_config_dsp_after_link_change_82541");
6848cfa0ad2SJack F Vogel 
6858cfa0ad2SJack F Vogel 	if (link_up) {
6868cfa0ad2SJack F Vogel 		ret_val = hw->mac.ops.get_link_up_info(hw, &speed, &duplex);
6878cfa0ad2SJack F Vogel 		if (ret_val) {
6888cfa0ad2SJack F Vogel 			DEBUGOUT("Error getting link speed and duplex\n");
6898cfa0ad2SJack F Vogel 			goto out;
6908cfa0ad2SJack F Vogel 		}
6918cfa0ad2SJack F Vogel 
6928cfa0ad2SJack F Vogel 		if (speed != SPEED_1000) {
6938cfa0ad2SJack F Vogel 			ret_val = E1000_SUCCESS;
6948cfa0ad2SJack F Vogel 			goto out;
6958cfa0ad2SJack F Vogel 		}
6968cfa0ad2SJack F Vogel 
6978cfa0ad2SJack F Vogel 		ret_val = phy->ops.get_cable_length(hw);
6988cfa0ad2SJack F Vogel 		if (ret_val)
6998cfa0ad2SJack F Vogel 			goto out;
7008cfa0ad2SJack F Vogel 
7018cfa0ad2SJack F Vogel 		if ((dev_spec->dsp_config == e1000_dsp_config_enabled) &&
7028cfa0ad2SJack F Vogel 		    phy->min_cable_length >= 50) {
7038cfa0ad2SJack F Vogel 
7048cfa0ad2SJack F Vogel 			for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
7058cfa0ad2SJack F Vogel 				ret_val = phy->ops.read_reg(hw,
7068cfa0ad2SJack F Vogel 							    dsp_reg_array[i],
7078cfa0ad2SJack F Vogel 							    &phy_data);
7088cfa0ad2SJack F Vogel 				if (ret_val)
7098cfa0ad2SJack F Vogel 					goto out;
7108cfa0ad2SJack F Vogel 
7118cfa0ad2SJack F Vogel 				phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
7128cfa0ad2SJack F Vogel 
7138cfa0ad2SJack F Vogel 				ret_val = phy->ops.write_reg(hw,
7148cfa0ad2SJack F Vogel 							     dsp_reg_array[i],
7158cfa0ad2SJack F Vogel 							     phy_data);
7168cfa0ad2SJack F Vogel 				if (ret_val)
7178cfa0ad2SJack F Vogel 					goto out;
7188cfa0ad2SJack F Vogel 			}
7198cfa0ad2SJack F Vogel 			dev_spec->dsp_config = e1000_dsp_config_activated;
7208cfa0ad2SJack F Vogel 		}
7218cfa0ad2SJack F Vogel 
7228cfa0ad2SJack F Vogel 		if ((dev_spec->ffe_config != e1000_ffe_config_enabled) ||
7238cfa0ad2SJack F Vogel 		    (phy->min_cable_length >= 50)) {
7248cfa0ad2SJack F Vogel 			ret_val = E1000_SUCCESS;
7258cfa0ad2SJack F Vogel 			goto out;
7268cfa0ad2SJack F Vogel 		}
7278cfa0ad2SJack F Vogel 
7288cfa0ad2SJack F Vogel 		/* clear previous idle error counts */
7298cfa0ad2SJack F Vogel 		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data);
7308cfa0ad2SJack F Vogel 		if (ret_val)
7318cfa0ad2SJack F Vogel 			goto out;
7328cfa0ad2SJack F Vogel 
7338cfa0ad2SJack F Vogel 		for (i = 0; i < ffe_idle_err_timeout; i++) {
7348cfa0ad2SJack F Vogel 			usec_delay(1000);
73548600901SSean Bruno 			ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS,
7368cfa0ad2SJack F Vogel 						    &phy_data);
7378cfa0ad2SJack F Vogel 			if (ret_val)
7388cfa0ad2SJack F Vogel 				goto out;
7398cfa0ad2SJack F Vogel 
7408cfa0ad2SJack F Vogel 			idle_errs += (phy_data & SR_1000T_IDLE_ERROR_CNT);
7418cfa0ad2SJack F Vogel 			if (idle_errs > SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT) {
7428cfa0ad2SJack F Vogel 				dev_spec->ffe_config = e1000_ffe_config_active;
7438cfa0ad2SJack F Vogel 
7448cfa0ad2SJack F Vogel 				ret_val = phy->ops.write_reg(hw,
7458cfa0ad2SJack F Vogel 						  IGP01E1000_PHY_DSP_FFE,
7468cfa0ad2SJack F Vogel 						  IGP01E1000_PHY_DSP_FFE_CM_CP);
7478cfa0ad2SJack F Vogel 				if (ret_val)
7488cfa0ad2SJack F Vogel 					goto out;
7498cfa0ad2SJack F Vogel 				break;
7508cfa0ad2SJack F Vogel 			}
7518cfa0ad2SJack F Vogel 
7528cfa0ad2SJack F Vogel 			if (idle_errs)
7538cfa0ad2SJack F Vogel 				ffe_idle_err_timeout =
7548cfa0ad2SJack F Vogel 						 FFE_IDLE_ERR_COUNT_TIMEOUT_100;
7558cfa0ad2SJack F Vogel 		}
7568cfa0ad2SJack F Vogel 	} else {
7578cfa0ad2SJack F Vogel 		if (dev_spec->dsp_config == e1000_dsp_config_activated) {
7588cfa0ad2SJack F Vogel 			/*
7598cfa0ad2SJack F Vogel 			 * Save off the current value of register 0x2F5B
7608cfa0ad2SJack F Vogel 			 * to be restored at the end of the routines.
7618cfa0ad2SJack F Vogel 			 */
76248600901SSean Bruno 			ret_val = phy->ops.read_reg(hw, 0x2F5B,
7638cfa0ad2SJack F Vogel 						    &phy_saved_data);
7648cfa0ad2SJack F Vogel 			if (ret_val)
7658cfa0ad2SJack F Vogel 				goto out;
7668cfa0ad2SJack F Vogel 
7678cfa0ad2SJack F Vogel 			/* Disable the PHY transmitter */
7688cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw, 0x2F5B, 0x0003);
7698cfa0ad2SJack F Vogel 			if (ret_val)
7708cfa0ad2SJack F Vogel 				goto out;
7718cfa0ad2SJack F Vogel 
7728cfa0ad2SJack F Vogel 			msec_delay_irq(20);
7738cfa0ad2SJack F Vogel 
77448600901SSean Bruno 			ret_val = phy->ops.write_reg(hw, 0x0000,
7758cfa0ad2SJack F Vogel 						     IGP01E1000_IEEE_FORCE_GIG);
7768cfa0ad2SJack F Vogel 			if (ret_val)
7778cfa0ad2SJack F Vogel 				goto out;
7788cfa0ad2SJack F Vogel 			for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
7798cfa0ad2SJack F Vogel 				ret_val = phy->ops.read_reg(hw,
7808cfa0ad2SJack F Vogel 							    dsp_reg_array[i],
7818cfa0ad2SJack F Vogel 							    &phy_data);
7828cfa0ad2SJack F Vogel 				if (ret_val)
7838cfa0ad2SJack F Vogel 					goto out;
7848cfa0ad2SJack F Vogel 
7858cfa0ad2SJack F Vogel 				phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
7868cfa0ad2SJack F Vogel 				phy_data |= IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS;
7878cfa0ad2SJack F Vogel 
7888cfa0ad2SJack F Vogel 				ret_val = phy->ops.write_reg(hw,
7898cfa0ad2SJack F Vogel 							     dsp_reg_array[i],
7908cfa0ad2SJack F Vogel 							     phy_data);
7918cfa0ad2SJack F Vogel 				if (ret_val)
7928cfa0ad2SJack F Vogel 					goto out;
7938cfa0ad2SJack F Vogel 			}
7948cfa0ad2SJack F Vogel 
79548600901SSean Bruno 			ret_val = phy->ops.write_reg(hw, 0x0000,
7968cfa0ad2SJack F Vogel 					       IGP01E1000_IEEE_RESTART_AUTONEG);
7978cfa0ad2SJack F Vogel 			if (ret_val)
7988cfa0ad2SJack F Vogel 				goto out;
7998cfa0ad2SJack F Vogel 
8008cfa0ad2SJack F Vogel 			msec_delay_irq(20);
8018cfa0ad2SJack F Vogel 
8028cfa0ad2SJack F Vogel 			/* Now enable the transmitter */
80348600901SSean Bruno 			ret_val = phy->ops.write_reg(hw, 0x2F5B,
8048cfa0ad2SJack F Vogel 						     phy_saved_data);
8058cfa0ad2SJack F Vogel 			if (ret_val)
8068cfa0ad2SJack F Vogel 				goto out;
8078cfa0ad2SJack F Vogel 
8088cfa0ad2SJack F Vogel 			dev_spec->dsp_config = e1000_dsp_config_enabled;
8098cfa0ad2SJack F Vogel 		}
8108cfa0ad2SJack F Vogel 
8118cfa0ad2SJack F Vogel 		if (dev_spec->ffe_config != e1000_ffe_config_active) {
8128cfa0ad2SJack F Vogel 			ret_val = E1000_SUCCESS;
8138cfa0ad2SJack F Vogel 			goto out;
8148cfa0ad2SJack F Vogel 		}
8158cfa0ad2SJack F Vogel 
8168cfa0ad2SJack F Vogel 		/*
8178cfa0ad2SJack F Vogel 		 * Save off the current value of register 0x2F5B
8188cfa0ad2SJack F Vogel 		 * to be restored at the end of the routines.
8198cfa0ad2SJack F Vogel 		 */
8208cfa0ad2SJack F Vogel 		ret_val = phy->ops.read_reg(hw, 0x2F5B, &phy_saved_data);
8218cfa0ad2SJack F Vogel 		if (ret_val)
8228cfa0ad2SJack F Vogel 			goto out;
8238cfa0ad2SJack F Vogel 
8248cfa0ad2SJack F Vogel 		/* Disable the PHY transmitter */
8258cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw, 0x2F5B, 0x0003);
8268cfa0ad2SJack F Vogel 		if (ret_val)
8278cfa0ad2SJack F Vogel 			goto out;
8288cfa0ad2SJack F Vogel 
8298cfa0ad2SJack F Vogel 		msec_delay_irq(20);
8308cfa0ad2SJack F Vogel 
83148600901SSean Bruno 		ret_val = phy->ops.write_reg(hw, 0x0000,
8328cfa0ad2SJack F Vogel 					     IGP01E1000_IEEE_FORCE_GIG);
8338cfa0ad2SJack F Vogel 		if (ret_val)
8348cfa0ad2SJack F Vogel 			goto out;
8358cfa0ad2SJack F Vogel 
83648600901SSean Bruno 		ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_DSP_FFE,
8378cfa0ad2SJack F Vogel 					     IGP01E1000_PHY_DSP_FFE_DEFAULT);
8388cfa0ad2SJack F Vogel 		if (ret_val)
8398cfa0ad2SJack F Vogel 			goto out;
8408cfa0ad2SJack F Vogel 
84148600901SSean Bruno 		ret_val = phy->ops.write_reg(hw, 0x0000,
8428cfa0ad2SJack F Vogel 					     IGP01E1000_IEEE_RESTART_AUTONEG);
8438cfa0ad2SJack F Vogel 		if (ret_val)
8448cfa0ad2SJack F Vogel 			goto out;
8458cfa0ad2SJack F Vogel 
8468cfa0ad2SJack F Vogel 		msec_delay_irq(20);
8478cfa0ad2SJack F Vogel 
8488cfa0ad2SJack F Vogel 		/* Now enable the transmitter */
8498cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw, 0x2F5B, phy_saved_data);
8508cfa0ad2SJack F Vogel 
8518cfa0ad2SJack F Vogel 		if (ret_val)
8528cfa0ad2SJack F Vogel 			goto out;
8538cfa0ad2SJack F Vogel 
8548cfa0ad2SJack F Vogel 		dev_spec->ffe_config = e1000_ffe_config_enabled;
8558cfa0ad2SJack F Vogel 	}
8568cfa0ad2SJack F Vogel 
8578cfa0ad2SJack F Vogel out:
8588cfa0ad2SJack F Vogel 	return ret_val;
8598cfa0ad2SJack F Vogel }
8608cfa0ad2SJack F Vogel 
8618cfa0ad2SJack F Vogel /**
8628cfa0ad2SJack F Vogel  *  e1000_get_cable_length_igp_82541 - Determine cable length for igp PHY
8638cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
8648cfa0ad2SJack F Vogel  *
8658cfa0ad2SJack F Vogel  *  The automatic gain control (agc) normalizes the amplitude of the
8668cfa0ad2SJack F Vogel  *  received signal, adjusting for the attenuation produced by the
8678cfa0ad2SJack F Vogel  *  cable.  By reading the AGC registers, which represent the
8688cfa0ad2SJack F Vogel  *  combination of coarse and fine gain value, the value can be put
8698cfa0ad2SJack F Vogel  *  into a lookup table to obtain the approximate cable length
870daf9197cSJack F Vogel  *  for each channel.
8718cfa0ad2SJack F Vogel  **/
e1000_get_cable_length_igp_82541(struct e1000_hw * hw)8728cfa0ad2SJack F Vogel static s32 e1000_get_cable_length_igp_82541(struct e1000_hw *hw)
8738cfa0ad2SJack F Vogel {
8748cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
8758cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
8768cfa0ad2SJack F Vogel 	u16 i, data;
8778cfa0ad2SJack F Vogel 	u16 cur_agc_value, agc_value = 0;
8788cfa0ad2SJack F Vogel 	u16 min_agc_value = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
87948600901SSean Bruno 	u16 agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] = {IGP01E1000_PHY_AGC_A,
8808cfa0ad2SJack F Vogel 							 IGP01E1000_PHY_AGC_B,
8818cfa0ad2SJack F Vogel 							 IGP01E1000_PHY_AGC_C,
8828cfa0ad2SJack F Vogel 							 IGP01E1000_PHY_AGC_D};
8838cfa0ad2SJack F Vogel 
8848cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_get_cable_length_igp_82541");
8858cfa0ad2SJack F Vogel 
8868cfa0ad2SJack F Vogel 	/* Read the AGC registers for all channels */
8878cfa0ad2SJack F Vogel 	for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
8888cfa0ad2SJack F Vogel 		ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &data);
8898cfa0ad2SJack F Vogel 		if (ret_val)
8908cfa0ad2SJack F Vogel 			goto out;
8918cfa0ad2SJack F Vogel 
8928cfa0ad2SJack F Vogel 		cur_agc_value = data >> IGP01E1000_AGC_LENGTH_SHIFT;
8938cfa0ad2SJack F Vogel 
8948cfa0ad2SJack F Vogel 		/* Bounds checking */
8958cfa0ad2SJack F Vogel 		if ((cur_agc_value >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) ||
8968cfa0ad2SJack F Vogel 		    (cur_agc_value == 0)) {
8978cfa0ad2SJack F Vogel 			ret_val = -E1000_ERR_PHY;
8988cfa0ad2SJack F Vogel 			goto out;
8998cfa0ad2SJack F Vogel 		}
9008cfa0ad2SJack F Vogel 
9018cfa0ad2SJack F Vogel 		agc_value += cur_agc_value;
9028cfa0ad2SJack F Vogel 
9038cfa0ad2SJack F Vogel 		if (min_agc_value > cur_agc_value)
9048cfa0ad2SJack F Vogel 			min_agc_value = cur_agc_value;
9058cfa0ad2SJack F Vogel 	}
9068cfa0ad2SJack F Vogel 
9078cfa0ad2SJack F Vogel 	/* Remove the minimal AGC result for length < 50m */
9088cfa0ad2SJack F Vogel 	if (agc_value < IGP01E1000_PHY_CHANNEL_NUM * 50) {
9098cfa0ad2SJack F Vogel 		agc_value -= min_agc_value;
9108cfa0ad2SJack F Vogel 		/* Average the three remaining channels for the length. */
9118cfa0ad2SJack F Vogel 		agc_value /= (IGP01E1000_PHY_CHANNEL_NUM - 1);
9128cfa0ad2SJack F Vogel 	} else {
9138cfa0ad2SJack F Vogel 		/* Average the channels for the length. */
9148cfa0ad2SJack F Vogel 		agc_value /= IGP01E1000_PHY_CHANNEL_NUM;
9158cfa0ad2SJack F Vogel 	}
9168cfa0ad2SJack F Vogel 
9178cfa0ad2SJack F Vogel 	phy->min_cable_length = (e1000_igp_cable_length_table[agc_value] >
9188cfa0ad2SJack F Vogel 				 IGP01E1000_AGC_RANGE)
9198cfa0ad2SJack F Vogel 				? (e1000_igp_cable_length_table[agc_value] -
9208cfa0ad2SJack F Vogel 				   IGP01E1000_AGC_RANGE)
9218cfa0ad2SJack F Vogel 				: 0;
9228cfa0ad2SJack F Vogel 	phy->max_cable_length = e1000_igp_cable_length_table[agc_value] +
9238cfa0ad2SJack F Vogel 				IGP01E1000_AGC_RANGE;
9248cfa0ad2SJack F Vogel 
9258cfa0ad2SJack F Vogel 	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
9268cfa0ad2SJack F Vogel 
9278cfa0ad2SJack F Vogel out:
9288cfa0ad2SJack F Vogel 	return ret_val;
9298cfa0ad2SJack F Vogel }
9308cfa0ad2SJack F Vogel 
9318cfa0ad2SJack F Vogel /**
9328cfa0ad2SJack F Vogel  *  e1000_set_d3_lplu_state_82541 - Sets low power link up state for D3
9338cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
9348cfa0ad2SJack F Vogel  *  @active: boolean used to enable/disable lplu
9358cfa0ad2SJack F Vogel  *
9368cfa0ad2SJack F Vogel  *  Success returns 0, Failure returns 1
9378cfa0ad2SJack F Vogel  *
9388cfa0ad2SJack F Vogel  *  The low power link up (lplu) state is set to the power management level D3
9391bbdc25fSKevin Bowling  *  and SmartSpeed is disabled when active is true, else clear lplu for D3
9408cfa0ad2SJack F Vogel  *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
9418cfa0ad2SJack F Vogel  *  is used during Dx states where the power conservation is most important.
9428cfa0ad2SJack F Vogel  *  During driver activity, SmartSpeed should be enabled so performance is
943daf9197cSJack F Vogel  *  maintained.
9448cfa0ad2SJack F Vogel  **/
e1000_set_d3_lplu_state_82541(struct e1000_hw * hw,bool active)9458cfa0ad2SJack F Vogel static s32 e1000_set_d3_lplu_state_82541(struct e1000_hw *hw, bool active)
9468cfa0ad2SJack F Vogel {
9478cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
9488cfa0ad2SJack F Vogel 	s32 ret_val;
9498cfa0ad2SJack F Vogel 	u16 data;
9508cfa0ad2SJack F Vogel 
9518cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_set_d3_lplu_state_82541");
9528cfa0ad2SJack F Vogel 
9538cfa0ad2SJack F Vogel 	switch (hw->mac.type) {
9548cfa0ad2SJack F Vogel 	case e1000_82541_rev_2:
9558cfa0ad2SJack F Vogel 	case e1000_82547_rev_2:
9568cfa0ad2SJack F Vogel 		break;
9578cfa0ad2SJack F Vogel 	default:
9588cfa0ad2SJack F Vogel 		ret_val = e1000_set_d3_lplu_state_generic(hw, active);
9598cfa0ad2SJack F Vogel 		goto out;
9608cfa0ad2SJack F Vogel 		break;
9618cfa0ad2SJack F Vogel 	}
9628cfa0ad2SJack F Vogel 
9638cfa0ad2SJack F Vogel 	ret_val = phy->ops.read_reg(hw, IGP01E1000_GMII_FIFO, &data);
9648cfa0ad2SJack F Vogel 	if (ret_val)
9658cfa0ad2SJack F Vogel 		goto out;
9668cfa0ad2SJack F Vogel 
9678cfa0ad2SJack F Vogel 	if (!active) {
9688cfa0ad2SJack F Vogel 		data &= ~IGP01E1000_GMII_FLEX_SPD;
9698cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw, IGP01E1000_GMII_FIFO, data);
9708cfa0ad2SJack F Vogel 		if (ret_val)
9718cfa0ad2SJack F Vogel 			goto out;
9728cfa0ad2SJack F Vogel 
9738cfa0ad2SJack F Vogel 		/*
9748cfa0ad2SJack F Vogel 		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
9758cfa0ad2SJack F Vogel 		 * during Dx states where the power conservation is most
9768cfa0ad2SJack F Vogel 		 * important.  During driver activity we should enable
9778cfa0ad2SJack F Vogel 		 * SmartSpeed, so performance is maintained.
9788cfa0ad2SJack F Vogel 		 */
9798cfa0ad2SJack F Vogel 		if (phy->smart_speed == e1000_smart_speed_on) {
9808cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
9818cfa0ad2SJack F Vogel 						    IGP01E1000_PHY_PORT_CONFIG,
9828cfa0ad2SJack F Vogel 						    &data);
9838cfa0ad2SJack F Vogel 			if (ret_val)
9848cfa0ad2SJack F Vogel 				goto out;
9858cfa0ad2SJack F Vogel 
9868cfa0ad2SJack F Vogel 			data |= IGP01E1000_PSCFR_SMART_SPEED;
9878cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
9888cfa0ad2SJack F Vogel 						     IGP01E1000_PHY_PORT_CONFIG,
9898cfa0ad2SJack F Vogel 						     data);
9908cfa0ad2SJack F Vogel 			if (ret_val)
9918cfa0ad2SJack F Vogel 				goto out;
9928cfa0ad2SJack F Vogel 		} else if (phy->smart_speed == e1000_smart_speed_off) {
9938cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
9948cfa0ad2SJack F Vogel 						    IGP01E1000_PHY_PORT_CONFIG,
9958cfa0ad2SJack F Vogel 						    &data);
9968cfa0ad2SJack F Vogel 			if (ret_val)
9978cfa0ad2SJack F Vogel 				goto out;
9988cfa0ad2SJack F Vogel 
9998cfa0ad2SJack F Vogel 			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
10008cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
10018cfa0ad2SJack F Vogel 						     IGP01E1000_PHY_PORT_CONFIG,
10028cfa0ad2SJack F Vogel 						     data);
10038cfa0ad2SJack F Vogel 			if (ret_val)
10048cfa0ad2SJack F Vogel 				goto out;
10058cfa0ad2SJack F Vogel 		}
10068cfa0ad2SJack F Vogel 	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
10078cfa0ad2SJack F Vogel 		   (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
10088cfa0ad2SJack F Vogel 		   (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
10098cfa0ad2SJack F Vogel 		data |= IGP01E1000_GMII_FLEX_SPD;
10108cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw, IGP01E1000_GMII_FIFO, data);
10118cfa0ad2SJack F Vogel 		if (ret_val)
10128cfa0ad2SJack F Vogel 			goto out;
10138cfa0ad2SJack F Vogel 
10148cfa0ad2SJack F Vogel 		/* When LPLU is enabled, we should disable SmartSpeed */
101548600901SSean Bruno 		ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
10168cfa0ad2SJack F Vogel 					    &data);
10178cfa0ad2SJack F Vogel 		if (ret_val)
10188cfa0ad2SJack F Vogel 			goto out;
10198cfa0ad2SJack F Vogel 
10208cfa0ad2SJack F Vogel 		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
102148600901SSean Bruno 		ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
10228cfa0ad2SJack F Vogel 					     data);
10238cfa0ad2SJack F Vogel 	}
10248cfa0ad2SJack F Vogel 
10258cfa0ad2SJack F Vogel out:
10268cfa0ad2SJack F Vogel 	return ret_val;
10278cfa0ad2SJack F Vogel }
10288cfa0ad2SJack F Vogel 
10298cfa0ad2SJack F Vogel /**
10308cfa0ad2SJack F Vogel  *  e1000_setup_led_82541 - Configures SW controllable LED
10318cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
10328cfa0ad2SJack F Vogel  *
10338cfa0ad2SJack F Vogel  *  This prepares the SW controllable LED for use and saves the current state
1034daf9197cSJack F Vogel  *  of the LED so it can be later restored.
10358cfa0ad2SJack F Vogel  **/
e1000_setup_led_82541(struct e1000_hw * hw)10368cfa0ad2SJack F Vogel static s32 e1000_setup_led_82541(struct e1000_hw *hw)
10378cfa0ad2SJack F Vogel {
1038daf9197cSJack F Vogel 	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
10398cfa0ad2SJack F Vogel 	s32 ret_val;
10408cfa0ad2SJack F Vogel 
10418cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_setup_led_82541");
10428cfa0ad2SJack F Vogel 
104348600901SSean Bruno 	ret_val = hw->phy.ops.read_reg(hw, IGP01E1000_GMII_FIFO,
10448cfa0ad2SJack F Vogel 				       &dev_spec->spd_default);
10458cfa0ad2SJack F Vogel 	if (ret_val)
10468cfa0ad2SJack F Vogel 		goto out;
10478cfa0ad2SJack F Vogel 
104848600901SSean Bruno 	ret_val = hw->phy.ops.write_reg(hw, IGP01E1000_GMII_FIFO,
10498cfa0ad2SJack F Vogel 					(u16)(dev_spec->spd_default &
10508cfa0ad2SJack F Vogel 					~IGP01E1000_GMII_SPD));
10518cfa0ad2SJack F Vogel 	if (ret_val)
10528cfa0ad2SJack F Vogel 		goto out;
10538cfa0ad2SJack F Vogel 
10548cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
10558cfa0ad2SJack F Vogel 
10568cfa0ad2SJack F Vogel out:
10578cfa0ad2SJack F Vogel 	return ret_val;
10588cfa0ad2SJack F Vogel }
10598cfa0ad2SJack F Vogel 
10608cfa0ad2SJack F Vogel /**
10618cfa0ad2SJack F Vogel  *  e1000_cleanup_led_82541 - Set LED config to default operation
10628cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
10638cfa0ad2SJack F Vogel  *
10648cfa0ad2SJack F Vogel  *  Remove the current LED configuration and set the LED configuration
1065daf9197cSJack F Vogel  *  to the default value, saved from the EEPROM.
10668cfa0ad2SJack F Vogel  **/
e1000_cleanup_led_82541(struct e1000_hw * hw)10678cfa0ad2SJack F Vogel static s32 e1000_cleanup_led_82541(struct e1000_hw *hw)
10688cfa0ad2SJack F Vogel {
1069daf9197cSJack F Vogel 	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
10708cfa0ad2SJack F Vogel 	s32 ret_val;
10718cfa0ad2SJack F Vogel 
10728cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_cleanup_led_82541");
10738cfa0ad2SJack F Vogel 
107448600901SSean Bruno 	ret_val = hw->phy.ops.write_reg(hw, IGP01E1000_GMII_FIFO,
10758cfa0ad2SJack F Vogel 					dev_spec->spd_default);
10768cfa0ad2SJack F Vogel 	if (ret_val)
10778cfa0ad2SJack F Vogel 		goto out;
10788cfa0ad2SJack F Vogel 
10798cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
10808cfa0ad2SJack F Vogel 
10818cfa0ad2SJack F Vogel out:
10828cfa0ad2SJack F Vogel 	return ret_val;
10838cfa0ad2SJack F Vogel }
10848cfa0ad2SJack F Vogel 
10858cfa0ad2SJack F Vogel /**
10868cfa0ad2SJack F Vogel  *  e1000_phy_init_script_82541 - Initialize GbE PHY
10878cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
10888cfa0ad2SJack F Vogel  *
10898cfa0ad2SJack F Vogel  *  Initializes the IGP PHY.
10908cfa0ad2SJack F Vogel  **/
e1000_phy_init_script_82541(struct e1000_hw * hw)10918cfa0ad2SJack F Vogel static s32 e1000_phy_init_script_82541(struct e1000_hw *hw)
10928cfa0ad2SJack F Vogel {
1093daf9197cSJack F Vogel 	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
10948cfa0ad2SJack F Vogel 	u32 ret_val;
10958cfa0ad2SJack F Vogel 	u16 phy_saved_data;
10968cfa0ad2SJack F Vogel 
10978cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_phy_init_script_82541");
10988cfa0ad2SJack F Vogel 
10998cfa0ad2SJack F Vogel 	if (!dev_spec->phy_init_script) {
11008cfa0ad2SJack F Vogel 		ret_val = E1000_SUCCESS;
11018cfa0ad2SJack F Vogel 		goto out;
11028cfa0ad2SJack F Vogel 	}
11038cfa0ad2SJack F Vogel 
11048cfa0ad2SJack F Vogel 	/* Delay after phy reset to enable NVM configuration to load */
11058cfa0ad2SJack F Vogel 	msec_delay(20);
11068cfa0ad2SJack F Vogel 
11078cfa0ad2SJack F Vogel 	/*
11088cfa0ad2SJack F Vogel 	 * Save off the current value of register 0x2F5B to be restored at
11098cfa0ad2SJack F Vogel 	 * the end of this routine.
11108cfa0ad2SJack F Vogel 	 */
11118cfa0ad2SJack F Vogel 	ret_val = hw->phy.ops.read_reg(hw, 0x2F5B, &phy_saved_data);
11128cfa0ad2SJack F Vogel 
11138cfa0ad2SJack F Vogel 	/* Disabled the PHY transmitter */
11148cfa0ad2SJack F Vogel 	hw->phy.ops.write_reg(hw, 0x2F5B, 0x0003);
11158cfa0ad2SJack F Vogel 
11168cfa0ad2SJack F Vogel 	msec_delay(20);
11178cfa0ad2SJack F Vogel 
11188cfa0ad2SJack F Vogel 	hw->phy.ops.write_reg(hw, 0x0000, 0x0140);
11198cfa0ad2SJack F Vogel 
11208cfa0ad2SJack F Vogel 	msec_delay(5);
11218cfa0ad2SJack F Vogel 
11228cfa0ad2SJack F Vogel 	switch (hw->mac.type) {
11238cfa0ad2SJack F Vogel 	case e1000_82541:
11248cfa0ad2SJack F Vogel 	case e1000_82547:
11258cfa0ad2SJack F Vogel 		hw->phy.ops.write_reg(hw, 0x1F95, 0x0001);
11268cfa0ad2SJack F Vogel 
11278cfa0ad2SJack F Vogel 		hw->phy.ops.write_reg(hw, 0x1F71, 0xBD21);
11288cfa0ad2SJack F Vogel 
11298cfa0ad2SJack F Vogel 		hw->phy.ops.write_reg(hw, 0x1F79, 0x0018);
11308cfa0ad2SJack F Vogel 
11318cfa0ad2SJack F Vogel 		hw->phy.ops.write_reg(hw, 0x1F30, 0x1600);
11328cfa0ad2SJack F Vogel 
11338cfa0ad2SJack F Vogel 		hw->phy.ops.write_reg(hw, 0x1F31, 0x0014);
11348cfa0ad2SJack F Vogel 
11358cfa0ad2SJack F Vogel 		hw->phy.ops.write_reg(hw, 0x1F32, 0x161C);
11368cfa0ad2SJack F Vogel 
11378cfa0ad2SJack F Vogel 		hw->phy.ops.write_reg(hw, 0x1F94, 0x0003);
11388cfa0ad2SJack F Vogel 
11398cfa0ad2SJack F Vogel 		hw->phy.ops.write_reg(hw, 0x1F96, 0x003F);
11408cfa0ad2SJack F Vogel 
11418cfa0ad2SJack F Vogel 		hw->phy.ops.write_reg(hw, 0x2010, 0x0008);
11428cfa0ad2SJack F Vogel 		break;
11438cfa0ad2SJack F Vogel 	case e1000_82541_rev_2:
11448cfa0ad2SJack F Vogel 	case e1000_82547_rev_2:
11458cfa0ad2SJack F Vogel 		hw->phy.ops.write_reg(hw, 0x1F73, 0x0099);
11468cfa0ad2SJack F Vogel 		break;
11478cfa0ad2SJack F Vogel 	default:
11488cfa0ad2SJack F Vogel 		break;
11498cfa0ad2SJack F Vogel 	}
11508cfa0ad2SJack F Vogel 
11518cfa0ad2SJack F Vogel 	hw->phy.ops.write_reg(hw, 0x0000, 0x3300);
11528cfa0ad2SJack F Vogel 
11538cfa0ad2SJack F Vogel 	msec_delay(20);
11548cfa0ad2SJack F Vogel 
11558cfa0ad2SJack F Vogel 	/* Now enable the transmitter */
11568cfa0ad2SJack F Vogel 	hw->phy.ops.write_reg(hw, 0x2F5B, phy_saved_data);
11578cfa0ad2SJack F Vogel 
11588cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_82547) {
11598cfa0ad2SJack F Vogel 		u16 fused, fine, coarse;
11608cfa0ad2SJack F Vogel 
11618cfa0ad2SJack F Vogel 		/* Move to analog registers page */
116248600901SSean Bruno 		hw->phy.ops.read_reg(hw, IGP01E1000_ANALOG_SPARE_FUSE_STATUS,
11638cfa0ad2SJack F Vogel 				     &fused);
11648cfa0ad2SJack F Vogel 
11658cfa0ad2SJack F Vogel 		if (!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) {
116648600901SSean Bruno 			hw->phy.ops.read_reg(hw, IGP01E1000_ANALOG_FUSE_STATUS,
11678cfa0ad2SJack F Vogel 					     &fused);
11688cfa0ad2SJack F Vogel 
11698cfa0ad2SJack F Vogel 			fine = fused & IGP01E1000_ANALOG_FUSE_FINE_MASK;
11708cfa0ad2SJack F Vogel 			coarse = fused & IGP01E1000_ANALOG_FUSE_COARSE_MASK;
11718cfa0ad2SJack F Vogel 
11728cfa0ad2SJack F Vogel 			if (coarse > IGP01E1000_ANALOG_FUSE_COARSE_THRESH) {
11738cfa0ad2SJack F Vogel 				coarse -= IGP01E1000_ANALOG_FUSE_COARSE_10;
11748cfa0ad2SJack F Vogel 				fine -= IGP01E1000_ANALOG_FUSE_FINE_1;
11758cfa0ad2SJack F Vogel 			} else if (coarse ==
11768cfa0ad2SJack F Vogel 				   IGP01E1000_ANALOG_FUSE_COARSE_THRESH)
11778cfa0ad2SJack F Vogel 				fine -= IGP01E1000_ANALOG_FUSE_FINE_10;
11788cfa0ad2SJack F Vogel 
11798cfa0ad2SJack F Vogel 			fused = (fused & IGP01E1000_ANALOG_FUSE_POLY_MASK) |
11808cfa0ad2SJack F Vogel 				(fine & IGP01E1000_ANALOG_FUSE_FINE_MASK) |
11818cfa0ad2SJack F Vogel 				(coarse & IGP01E1000_ANALOG_FUSE_COARSE_MASK);
11828cfa0ad2SJack F Vogel 
11838cfa0ad2SJack F Vogel 			hw->phy.ops.write_reg(hw,
11848cfa0ad2SJack F Vogel 					      IGP01E1000_ANALOG_FUSE_CONTROL,
11858cfa0ad2SJack F Vogel 					      fused);
11868cfa0ad2SJack F Vogel 			hw->phy.ops.write_reg(hw,
11878cfa0ad2SJack F Vogel 				      IGP01E1000_ANALOG_FUSE_BYPASS,
11888cfa0ad2SJack F Vogel 				      IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL);
11898cfa0ad2SJack F Vogel 		}
11908cfa0ad2SJack F Vogel 	}
11918cfa0ad2SJack F Vogel 
11928cfa0ad2SJack F Vogel out:
11938cfa0ad2SJack F Vogel 	return ret_val;
11948cfa0ad2SJack F Vogel }
11958cfa0ad2SJack F Vogel 
11968cfa0ad2SJack F Vogel /**
11978cfa0ad2SJack F Vogel  *  e1000_init_script_state_82541 - Enable/Disable PHY init script
11988cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
11998cfa0ad2SJack F Vogel  *  @state: boolean value used to enable/disable PHY init script
12008cfa0ad2SJack F Vogel  *
12018cfa0ad2SJack F Vogel  *  Allows the driver to enable/disable the PHY init script, if the PHY is an
1202daf9197cSJack F Vogel  *  IGP PHY.
12038cfa0ad2SJack F Vogel  **/
e1000_init_script_state_82541(struct e1000_hw * hw,bool state)12048cfa0ad2SJack F Vogel void e1000_init_script_state_82541(struct e1000_hw *hw, bool state)
12058cfa0ad2SJack F Vogel {
1206daf9197cSJack F Vogel 	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
12078cfa0ad2SJack F Vogel 
12088cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_script_state_82541");
12098cfa0ad2SJack F Vogel 
12108cfa0ad2SJack F Vogel 	if (hw->phy.type != e1000_phy_igp) {
12118cfa0ad2SJack F Vogel 		DEBUGOUT("Initialization script not necessary.\n");
12128cfa0ad2SJack F Vogel 		goto out;
12138cfa0ad2SJack F Vogel 	}
12148cfa0ad2SJack F Vogel 
12158cfa0ad2SJack F Vogel 	dev_spec->phy_init_script = state;
12168cfa0ad2SJack F Vogel 
12178cfa0ad2SJack F Vogel out:
12188cfa0ad2SJack F Vogel 	return;
12198cfa0ad2SJack F Vogel }
12208cfa0ad2SJack F Vogel 
12218cfa0ad2SJack F Vogel /**
12228cfa0ad2SJack F Vogel  * e1000_power_down_phy_copper_82541 - Remove link in case of PHY power down
12238cfa0ad2SJack F Vogel  * @hw: pointer to the HW structure
12248cfa0ad2SJack F Vogel  *
12258cfa0ad2SJack F Vogel  * In the case of a PHY power down to save power, or to turn off link during a
12268cfa0ad2SJack F Vogel  * driver unload, or wake on lan is not enabled, remove the link.
12278cfa0ad2SJack F Vogel  **/
e1000_power_down_phy_copper_82541(struct e1000_hw * hw)12288cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_82541(struct e1000_hw *hw)
12298cfa0ad2SJack F Vogel {
12308cfa0ad2SJack F Vogel 	/* If the management interface is not enabled, then power down */
12318cfa0ad2SJack F Vogel 	if (!(E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_SMBUS_EN))
12328cfa0ad2SJack F Vogel 		e1000_power_down_phy_copper(hw);
12338cfa0ad2SJack F Vogel 
12348cfa0ad2SJack F Vogel 	return;
12358cfa0ad2SJack F Vogel }
12368cfa0ad2SJack F Vogel 
12378cfa0ad2SJack F Vogel /**
12388cfa0ad2SJack F Vogel  *  e1000_clear_hw_cntrs_82541 - Clear device specific hardware counters
12398cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
12408cfa0ad2SJack F Vogel  *
12418cfa0ad2SJack F Vogel  *  Clears the hardware counters by reading the counter registers.
12428cfa0ad2SJack F Vogel  **/
e1000_clear_hw_cntrs_82541(struct e1000_hw * hw)12438cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_82541(struct e1000_hw *hw)
12448cfa0ad2SJack F Vogel {
12458cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_clear_hw_cntrs_82541");
12468cfa0ad2SJack F Vogel 
12478cfa0ad2SJack F Vogel 	e1000_clear_hw_cntrs_base_generic(hw);
12488cfa0ad2SJack F Vogel 
1249daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PRC64);
1250daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PRC127);
1251daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PRC255);
1252daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PRC511);
1253daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PRC1023);
1254daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PRC1522);
1255daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PTC64);
1256daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PTC127);
1257daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PTC255);
1258daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PTC511);
1259daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PTC1023);
1260daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PTC1522);
12618cfa0ad2SJack F Vogel 
1262daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_ALGNERRC);
1263daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_RXERRC);
1264daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TNCRS);
1265daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_CEXTERR);
1266daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TSCTC);
1267daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TSCTFC);
12688cfa0ad2SJack F Vogel 
1269daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPRC);
1270daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPDC);
1271daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPTC);
12728cfa0ad2SJack F Vogel }
12734edd8523SJack F Vogel 
12744edd8523SJack F Vogel /**
12754edd8523SJack F Vogel  *  e1000_read_mac_addr_82541 - Read device MAC address
12764edd8523SJack F Vogel  *  @hw: pointer to the HW structure
12774edd8523SJack F Vogel  *
12784edd8523SJack F Vogel  *  Reads the device MAC address from the EEPROM and stores the value.
12794edd8523SJack F Vogel  **/
e1000_read_mac_addr_82541(struct e1000_hw * hw)12804edd8523SJack F Vogel static s32 e1000_read_mac_addr_82541(struct e1000_hw *hw)
12814edd8523SJack F Vogel {
12824edd8523SJack F Vogel 	s32  ret_val = E1000_SUCCESS;
12834edd8523SJack F Vogel 	u16 offset, nvm_data, i;
12844edd8523SJack F Vogel 
12854edd8523SJack F Vogel 	DEBUGFUNC("e1000_read_mac_addr");
12864edd8523SJack F Vogel 
1287e81998f4SEric Joyner 	for (i = 0; i < ETHER_ADDR_LEN; i += 2) {
12884edd8523SJack F Vogel 		offset = i >> 1;
12894edd8523SJack F Vogel 		ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
12904edd8523SJack F Vogel 		if (ret_val) {
12914edd8523SJack F Vogel 			DEBUGOUT("NVM Read Error\n");
12924edd8523SJack F Vogel 			goto out;
12934edd8523SJack F Vogel 		}
12944edd8523SJack F Vogel 		hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF);
12954edd8523SJack F Vogel 		hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8);
12964edd8523SJack F Vogel 	}
12974edd8523SJack F Vogel 
1298e81998f4SEric Joyner 	for (i = 0; i < ETHER_ADDR_LEN; i++)
12994edd8523SJack F Vogel 		hw->mac.addr[i] = hw->mac.perm_addr[i];
13004edd8523SJack F Vogel 
13014edd8523SJack F Vogel out:
13024edd8523SJack F Vogel 	return ret_val;
13034edd8523SJack F Vogel }
13044edd8523SJack F Vogel 
1305