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