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