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
356ab6bfe3SJack F Vogel /* 82562G 10/100 Network Connection
36daf9197cSJack F Vogel * 82562G-2 10/100 Network Connection
37daf9197cSJack F Vogel * 82562GT 10/100 Network Connection
38daf9197cSJack F Vogel * 82562GT-2 10/100 Network Connection
39daf9197cSJack F Vogel * 82562V 10/100 Network Connection
40daf9197cSJack F Vogel * 82562V-2 10/100 Network Connection
41daf9197cSJack F Vogel * 82566DC-2 Gigabit Network Connection
42daf9197cSJack F Vogel * 82566DC Gigabit Network Connection
43daf9197cSJack F Vogel * 82566DM-2 Gigabit Network Connection
44daf9197cSJack F Vogel * 82566DM Gigabit Network Connection
45daf9197cSJack F Vogel * 82566MC Gigabit Network Connection
46daf9197cSJack F Vogel * 82566MM Gigabit Network Connection
47daf9197cSJack F Vogel * 82567LM Gigabit Network Connection
48daf9197cSJack F Vogel * 82567LF Gigabit Network Connection
49daf9197cSJack F Vogel * 82567V Gigabit Network Connection
50daf9197cSJack F Vogel * 82567LM-2 Gigabit Network Connection
51daf9197cSJack F Vogel * 82567LF-2 Gigabit Network Connection
52daf9197cSJack F Vogel * 82567V-2 Gigabit Network Connection
53daf9197cSJack F Vogel * 82567LF-3 Gigabit Network Connection
54daf9197cSJack F Vogel * 82567LM-3 Gigabit Network Connection
55daf9197cSJack F Vogel * 82567LM-4 Gigabit Network Connection
569d81738fSJack F Vogel * 82577LM Gigabit Network Connection
579d81738fSJack F Vogel * 82577LC Gigabit Network Connection
589d81738fSJack F Vogel * 82578DM Gigabit Network Connection
599d81738fSJack F Vogel * 82578DC Gigabit Network Connection
607d9119bdSJack F Vogel * 82579LM Gigabit Network Connection
617d9119bdSJack F Vogel * 82579V Gigabit Network Connection
627609433eSJack F Vogel * Ethernet Connection I217-LM
637609433eSJack F Vogel * Ethernet Connection I217-V
647609433eSJack F Vogel * Ethernet Connection I218-V
657609433eSJack F Vogel * Ethernet Connection I218-LM
668cc64f1eSJack F Vogel * Ethernet Connection (2) I218-LM
678cc64f1eSJack F Vogel * Ethernet Connection (2) I218-V
688cc64f1eSJack F Vogel * Ethernet Connection (3) I218-LM
698cc64f1eSJack F Vogel * Ethernet Connection (3) I218-V
708cfa0ad2SJack F Vogel */
718cfa0ad2SJack F Vogel
728cfa0ad2SJack F Vogel #include "e1000_api.h"
738cfa0ad2SJack F Vogel
74d36fbdb0SKevin Bowling static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state);
758cfa0ad2SJack F Vogel static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw);
768cfa0ad2SJack F Vogel static void e1000_release_swflag_ich8lan(struct e1000_hw *hw);
774edd8523SJack F Vogel static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw);
784edd8523SJack F Vogel static void e1000_release_nvm_ich8lan(struct e1000_hw *hw);
798cfa0ad2SJack F Vogel static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw);
807d9119bdSJack F Vogel static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw);
818cc64f1eSJack F Vogel static int e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index);
828cc64f1eSJack F Vogel static int e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index);
837609433eSJack F Vogel static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw);
84730d3130SJack F Vogel static void e1000_update_mc_addr_list_pch2lan(struct e1000_hw *hw,
85730d3130SJack F Vogel u8 *mc_addr_list,
86730d3130SJack F Vogel u32 mc_addr_count);
878cfa0ad2SJack F Vogel static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw);
888cfa0ad2SJack F Vogel static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw);
894edd8523SJack F Vogel static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active);
908cfa0ad2SJack F Vogel static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw,
918cfa0ad2SJack F Vogel bool active);
928cfa0ad2SJack F Vogel static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw,
938cfa0ad2SJack F Vogel bool active);
948cfa0ad2SJack F Vogel static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
958cfa0ad2SJack F Vogel u16 words, u16 *data);
96c80429ceSEric Joyner static s32 e1000_read_nvm_spt(struct e1000_hw *hw, u16 offset, u16 words,
97c80429ceSEric Joyner u16 *data);
988cfa0ad2SJack F Vogel static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
998cfa0ad2SJack F Vogel u16 words, u16 *data);
1008cfa0ad2SJack F Vogel static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw);
1018cfa0ad2SJack F Vogel static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw);
102c80429ceSEric Joyner static s32 e1000_update_nvm_checksum_spt(struct e1000_hw *hw);
1038cfa0ad2SJack F Vogel static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw,
1048cfa0ad2SJack F Vogel u16 *data);
1059d81738fSJack F Vogel static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw);
1068cfa0ad2SJack F Vogel static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw);
1078cfa0ad2SJack F Vogel static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw);
1088cfa0ad2SJack F Vogel static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw);
1098cfa0ad2SJack F Vogel static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw);
1108cfa0ad2SJack F Vogel static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
1116ab6bfe3SJack F Vogel static s32 e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw);
1128cfa0ad2SJack F Vogel static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw,
1138cfa0ad2SJack F Vogel u16 *speed, u16 *duplex);
1148cfa0ad2SJack F Vogel static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw);
1158cfa0ad2SJack F Vogel static s32 e1000_led_on_ich8lan(struct e1000_hw *hw);
1168cfa0ad2SJack F Vogel static s32 e1000_led_off_ich8lan(struct e1000_hw *hw);
1174edd8523SJack F Vogel static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link);
1189d81738fSJack F Vogel static s32 e1000_setup_led_pchlan(struct e1000_hw *hw);
1199d81738fSJack F Vogel static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw);
1209d81738fSJack F Vogel static s32 e1000_led_on_pchlan(struct e1000_hw *hw);
1219d81738fSJack F Vogel static s32 e1000_led_off_pchlan(struct e1000_hw *hw);
1228cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
1238cfa0ad2SJack F Vogel static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank);
1248cfa0ad2SJack F Vogel static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
1258cfa0ad2SJack F Vogel static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
1268cfa0ad2SJack F Vogel static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw,
1278cfa0ad2SJack F Vogel u32 offset, u8 *data);
1288cfa0ad2SJack F Vogel static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
1298cfa0ad2SJack F Vogel u8 size, u16 *data);
130c80429ceSEric Joyner static s32 e1000_read_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset,
131c80429ceSEric Joyner u32 *data);
132c80429ceSEric Joyner static s32 e1000_read_flash_dword_ich8lan(struct e1000_hw *hw,
133c80429ceSEric Joyner u32 offset, u32 *data);
134c80429ceSEric Joyner static s32 e1000_write_flash_data32_ich8lan(struct e1000_hw *hw,
135c80429ceSEric Joyner u32 offset, u32 data);
136c80429ceSEric Joyner static s32 e1000_retry_write_flash_dword_ich8lan(struct e1000_hw *hw,
137c80429ceSEric Joyner u32 offset, u32 dword);
1388cfa0ad2SJack F Vogel static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw,
1398cfa0ad2SJack F Vogel u32 offset, u16 *data);
1408cfa0ad2SJack F Vogel static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
1418cfa0ad2SJack F Vogel u32 offset, u8 byte);
1428cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw);
1438cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw);
1444edd8523SJack F Vogel static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw);
145a69ed8dfSJack F Vogel static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw);
1467d9119bdSJack F Vogel static s32 e1000_k1_workaround_lv(struct e1000_hw *hw);
1477d9119bdSJack F Vogel static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate);
148e373323fSSean Bruno static s32 e1000_set_obff_timer_pch_lpt(struct e1000_hw *hw, u32 itr);
1498cfa0ad2SJack F Vogel
1508cfa0ad2SJack F Vogel /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
1518cfa0ad2SJack F Vogel /* Offset 04h HSFSTS */
1528cfa0ad2SJack F Vogel union ich8_hws_flash_status {
1538cfa0ad2SJack F Vogel struct ich8_hsfsts {
1548cfa0ad2SJack F Vogel u16 flcdone:1; /* bit 0 Flash Cycle Done */
1558cfa0ad2SJack F Vogel u16 flcerr:1; /* bit 1 Flash Cycle Error */
1568cfa0ad2SJack F Vogel u16 dael:1; /* bit 2 Direct Access error Log */
1578cfa0ad2SJack F Vogel u16 berasesz:2; /* bit 4:3 Sector Erase Size */
1588cfa0ad2SJack F Vogel u16 flcinprog:1; /* bit 5 flash cycle in Progress */
1598cfa0ad2SJack F Vogel u16 reserved1:2; /* bit 13:6 Reserved */
1608cfa0ad2SJack F Vogel u16 reserved2:6; /* bit 13:6 Reserved */
1618cfa0ad2SJack F Vogel u16 fldesvalid:1; /* bit 14 Flash Descriptor Valid */
1628cfa0ad2SJack F Vogel u16 flockdn:1; /* bit 15 Flash Config Lock-Down */
1638cfa0ad2SJack F Vogel } hsf_status;
1648cfa0ad2SJack F Vogel u16 regval;
1658cfa0ad2SJack F Vogel };
1668cfa0ad2SJack F Vogel
1678cfa0ad2SJack F Vogel /* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */
1688cfa0ad2SJack F Vogel /* Offset 06h FLCTL */
1698cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl {
1708cfa0ad2SJack F Vogel struct ich8_hsflctl {
1718cfa0ad2SJack F Vogel u16 flcgo:1; /* 0 Flash Cycle Go */
1728cfa0ad2SJack F Vogel u16 flcycle:2; /* 2:1 Flash Cycle */
1738cfa0ad2SJack F Vogel u16 reserved:5; /* 7:3 Reserved */
1748cfa0ad2SJack F Vogel u16 fldbcount:2; /* 9:8 Flash Data Byte Count */
1758cfa0ad2SJack F Vogel u16 flockdn:6; /* 15:10 Reserved */
1768cfa0ad2SJack F Vogel } hsf_ctrl;
1778cfa0ad2SJack F Vogel u16 regval;
1788cfa0ad2SJack F Vogel };
1798cfa0ad2SJack F Vogel
1808cfa0ad2SJack F Vogel /* ICH Flash Region Access Permissions */
1818cfa0ad2SJack F Vogel union ich8_hws_flash_regacc {
1828cfa0ad2SJack F Vogel struct ich8_flracc {
1838cfa0ad2SJack F Vogel u32 grra:8; /* 0:7 GbE region Read Access */
1848cfa0ad2SJack F Vogel u32 grwa:8; /* 8:15 GbE region Write Access */
1858cfa0ad2SJack F Vogel u32 gmrag:8; /* 23:16 GbE Master Read Access Grant */
1868cfa0ad2SJack F Vogel u32 gmwag:8; /* 31:24 GbE Master Write Access Grant */
1878cfa0ad2SJack F Vogel } hsf_flregacc;
1888cfa0ad2SJack F Vogel u16 regval;
1898cfa0ad2SJack F Vogel };
1908cfa0ad2SJack F Vogel
1916ab6bfe3SJack F Vogel /**
1926ab6bfe3SJack F Vogel * e1000_phy_is_accessible_pchlan - Check if able to access PHY registers
1936ab6bfe3SJack F Vogel * @hw: pointer to the HW structure
1946ab6bfe3SJack F Vogel *
1956ab6bfe3SJack F Vogel * Test access to the PHY registers by reading the PHY ID registers. If
1966ab6bfe3SJack F Vogel * the PHY ID is already known (e.g. resume path) compare it with known ID,
1976ab6bfe3SJack F Vogel * otherwise assume the read PHY ID is correct if it is valid.
1986ab6bfe3SJack F Vogel *
1996ab6bfe3SJack F Vogel * Assumes the sw/fw/hw semaphore is already acquired.
2006ab6bfe3SJack F Vogel **/
e1000_phy_is_accessible_pchlan(struct e1000_hw * hw)2016ab6bfe3SJack F Vogel static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw)
2024dab5c37SJack F Vogel {
2036ab6bfe3SJack F Vogel u16 phy_reg = 0;
2046ab6bfe3SJack F Vogel u32 phy_id = 0;
2057609433eSJack F Vogel s32 ret_val = 0;
2066ab6bfe3SJack F Vogel u16 retry_count;
2077609433eSJack F Vogel u32 mac_reg = 0;
2084dab5c37SJack F Vogel
2096ab6bfe3SJack F Vogel for (retry_count = 0; retry_count < 2; retry_count++) {
2106ab6bfe3SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID1, &phy_reg);
2116ab6bfe3SJack F Vogel if (ret_val || (phy_reg == 0xFFFF))
2126ab6bfe3SJack F Vogel continue;
2136ab6bfe3SJack F Vogel phy_id = (u32)(phy_reg << 16);
2144dab5c37SJack F Vogel
2156ab6bfe3SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID2, &phy_reg);
2166ab6bfe3SJack F Vogel if (ret_val || (phy_reg == 0xFFFF)) {
2176ab6bfe3SJack F Vogel phy_id = 0;
2186ab6bfe3SJack F Vogel continue;
2196ab6bfe3SJack F Vogel }
2206ab6bfe3SJack F Vogel phy_id |= (u32)(phy_reg & PHY_REVISION_MASK);
2216ab6bfe3SJack F Vogel break;
2226ab6bfe3SJack F Vogel }
2236ab6bfe3SJack F Vogel
2246ab6bfe3SJack F Vogel if (hw->phy.id) {
2256ab6bfe3SJack F Vogel if (hw->phy.id == phy_id)
2267609433eSJack F Vogel goto out;
2276ab6bfe3SJack F Vogel } else if (phy_id) {
2286ab6bfe3SJack F Vogel hw->phy.id = phy_id;
2296ab6bfe3SJack F Vogel hw->phy.revision = (u32)(phy_reg & ~PHY_REVISION_MASK);
2307609433eSJack F Vogel goto out;
2316ab6bfe3SJack F Vogel }
2326ab6bfe3SJack F Vogel
2336ab6bfe3SJack F Vogel /* In case the PHY needs to be in mdio slow mode,
2346ab6bfe3SJack F Vogel * set slow mode and try to get the PHY id again.
2356ab6bfe3SJack F Vogel */
2367609433eSJack F Vogel if (hw->mac.type < e1000_pch_lpt) {
2376ab6bfe3SJack F Vogel hw->phy.ops.release(hw);
2386ab6bfe3SJack F Vogel ret_val = e1000_set_mdio_slow_mode_hv(hw);
2396ab6bfe3SJack F Vogel if (!ret_val)
2406ab6bfe3SJack F Vogel ret_val = e1000_get_phy_id(hw);
2416ab6bfe3SJack F Vogel hw->phy.ops.acquire(hw);
2427609433eSJack F Vogel }
2436ab6bfe3SJack F Vogel
2447609433eSJack F Vogel if (ret_val)
2451bbdc25fSKevin Bowling return false;
2467609433eSJack F Vogel out:
247295df609SEric Joyner if (hw->mac.type >= e1000_pch_lpt) {
248c80429ceSEric Joyner /* Only unforce SMBus if ME is not active */
249c80429ceSEric Joyner if (!(E1000_READ_REG(hw, E1000_FWSM) &
250c80429ceSEric Joyner E1000_ICH_FWSM_FW_VALID)) {
2517609433eSJack F Vogel /* Unforce SMBus mode in PHY */
2527609433eSJack F Vogel hw->phy.ops.read_reg_locked(hw, CV_SMB_CTRL, &phy_reg);
2537609433eSJack F Vogel phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
2547609433eSJack F Vogel hw->phy.ops.write_reg_locked(hw, CV_SMB_CTRL, phy_reg);
2557609433eSJack F Vogel
2567609433eSJack F Vogel /* Unforce SMBus mode in MAC */
2577609433eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
2587609433eSJack F Vogel mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
2597609433eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
2607609433eSJack F Vogel }
261c80429ceSEric Joyner }
2627609433eSJack F Vogel
2631bbdc25fSKevin Bowling return true;
2647609433eSJack F Vogel }
2657609433eSJack F Vogel
2667609433eSJack F Vogel /**
2677609433eSJack F Vogel * e1000_toggle_lanphypc_pch_lpt - toggle the LANPHYPC pin value
2687609433eSJack F Vogel * @hw: pointer to the HW structure
2697609433eSJack F Vogel *
2707609433eSJack F Vogel * Toggling the LANPHYPC pin value fully power-cycles the PHY and is
2717609433eSJack F Vogel * used to reset the PHY to a quiescent state when necessary.
2727609433eSJack F Vogel **/
e1000_toggle_lanphypc_pch_lpt(struct e1000_hw * hw)2738cc64f1eSJack F Vogel static void e1000_toggle_lanphypc_pch_lpt(struct e1000_hw *hw)
2747609433eSJack F Vogel {
2757609433eSJack F Vogel u32 mac_reg;
2767609433eSJack F Vogel
2777609433eSJack F Vogel DEBUGFUNC("e1000_toggle_lanphypc_pch_lpt");
2787609433eSJack F Vogel
2797609433eSJack F Vogel /* Set Phy Config Counter to 50msec */
2807609433eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM3);
2817609433eSJack F Vogel mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK;
2827609433eSJack F Vogel mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
2837609433eSJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM3, mac_reg);
2847609433eSJack F Vogel
2857609433eSJack F Vogel /* Toggle LANPHYPC Value bit */
2867609433eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_CTRL);
2877609433eSJack F Vogel mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE;
2887609433eSJack F Vogel mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE;
2897609433eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, mac_reg);
2907609433eSJack F Vogel E1000_WRITE_FLUSH(hw);
291e760e292SSean Bruno msec_delay(1);
2927609433eSJack F Vogel mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
2937609433eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, mac_reg);
2947609433eSJack F Vogel E1000_WRITE_FLUSH(hw);
2957609433eSJack F Vogel
2967609433eSJack F Vogel if (hw->mac.type < e1000_pch_lpt) {
2977609433eSJack F Vogel msec_delay(50);
2987609433eSJack F Vogel } else {
2997609433eSJack F Vogel u16 count = 20;
3007609433eSJack F Vogel
3017609433eSJack F Vogel do {
3027609433eSJack F Vogel msec_delay(5);
3037609433eSJack F Vogel } while (!(E1000_READ_REG(hw, E1000_CTRL_EXT) &
3047609433eSJack F Vogel E1000_CTRL_EXT_LPCD) && count--);
3057609433eSJack F Vogel
3067609433eSJack F Vogel msec_delay(30);
3077609433eSJack F Vogel }
3086ab6bfe3SJack F Vogel }
3096ab6bfe3SJack F Vogel
3106ab6bfe3SJack F Vogel /**
3116ab6bfe3SJack F Vogel * e1000_init_phy_workarounds_pchlan - PHY initialization workarounds
3126ab6bfe3SJack F Vogel * @hw: pointer to the HW structure
3136ab6bfe3SJack F Vogel *
3146ab6bfe3SJack F Vogel * Workarounds/flow necessary for PHY initialization during driver load
3156ab6bfe3SJack F Vogel * and resume paths.
3166ab6bfe3SJack F Vogel **/
e1000_init_phy_workarounds_pchlan(struct e1000_hw * hw)3176ab6bfe3SJack F Vogel static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
3186ab6bfe3SJack F Vogel {
3196ab6bfe3SJack F Vogel u32 mac_reg, fwsm = E1000_READ_REG(hw, E1000_FWSM);
3206ab6bfe3SJack F Vogel s32 ret_val;
3216ab6bfe3SJack F Vogel
3226ab6bfe3SJack F Vogel DEBUGFUNC("e1000_init_phy_workarounds_pchlan");
3236ab6bfe3SJack F Vogel
3246ab6bfe3SJack F Vogel /* Gate automatic PHY configuration by hardware on managed and
3256ab6bfe3SJack F Vogel * non-managed 82579 and newer adapters.
3266ab6bfe3SJack F Vogel */
3271bbdc25fSKevin Bowling e1000_gate_hw_phy_config_ich8lan(hw, true);
3286ab6bfe3SJack F Vogel
3298cc64f1eSJack F Vogel /* It is not possible to be certain of the current state of ULP
3308cc64f1eSJack F Vogel * so forcibly disable it.
3318cc64f1eSJack F Vogel */
3328cc64f1eSJack F Vogel hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_unknown;
333d36fbdb0SKevin Bowling ret_val = e1000_disable_ulp_lpt_lp(hw, true);
334d36fbdb0SKevin Bowling if (ret_val)
335d36fbdb0SKevin Bowling ERROR_REPORT("Failed to disable ULP\n");
3368cc64f1eSJack F Vogel
3376ab6bfe3SJack F Vogel ret_val = hw->phy.ops.acquire(hw);
3386ab6bfe3SJack F Vogel if (ret_val) {
3396ab6bfe3SJack F Vogel DEBUGOUT("Failed to initialize PHY flow\n");
3406ab6bfe3SJack F Vogel goto out;
3416ab6bfe3SJack F Vogel }
3426ab6bfe3SJack F Vogel
3436ab6bfe3SJack F Vogel /* The MAC-PHY interconnect may be in SMBus mode. If the PHY is
3446ab6bfe3SJack F Vogel * inaccessible and resetting the PHY is not blocked, toggle the
3456ab6bfe3SJack F Vogel * LANPHYPC Value bit to force the interconnect to PCIe mode.
3466ab6bfe3SJack F Vogel */
3476ab6bfe3SJack F Vogel switch (hw->mac.type) {
3486ab6bfe3SJack F Vogel case e1000_pch_lpt:
349c80429ceSEric Joyner case e1000_pch_spt:
3506fe4c0a0SSean Bruno case e1000_pch_cnp:
35159690eabSKevin Bowling case e1000_pch_tgp:
35259690eabSKevin Bowling case e1000_pch_adp:
35359690eabSKevin Bowling case e1000_pch_mtp:
354*905ae588SKevin Bowling case e1000_pch_ptp:
3556ab6bfe3SJack F Vogel if (e1000_phy_is_accessible_pchlan(hw))
3566ab6bfe3SJack F Vogel break;
3576ab6bfe3SJack F Vogel
3586ab6bfe3SJack F Vogel /* Before toggling LANPHYPC, see if PHY is accessible by
3596ab6bfe3SJack F Vogel * forcing MAC to SMBus mode first.
3606ab6bfe3SJack F Vogel */
3616ab6bfe3SJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
3626ab6bfe3SJack F Vogel mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
3636ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
3646ab6bfe3SJack F Vogel
3657609433eSJack F Vogel /* Wait 50 milliseconds for MAC to finish any retries
3667609433eSJack F Vogel * that it might be trying to perform from previous
3677609433eSJack F Vogel * attempts to acknowledge any phy read requests.
3687609433eSJack F Vogel */
3697609433eSJack F Vogel msec_delay(50);
3707609433eSJack F Vogel
371e05d9788SKevin Bowling /* FALLTHROUGH */
3726ab6bfe3SJack F Vogel case e1000_pch2lan:
3737609433eSJack F Vogel if (e1000_phy_is_accessible_pchlan(hw))
3746ab6bfe3SJack F Vogel break;
3756ab6bfe3SJack F Vogel
376e05d9788SKevin Bowling /* FALLTHROUGH */
3776ab6bfe3SJack F Vogel case e1000_pchlan:
3786ab6bfe3SJack F Vogel if ((hw->mac.type == e1000_pchlan) &&
3796ab6bfe3SJack F Vogel (fwsm & E1000_ICH_FWSM_FW_VALID))
3806ab6bfe3SJack F Vogel break;
3816ab6bfe3SJack F Vogel
3826ab6bfe3SJack F Vogel if (hw->phy.ops.check_reset_block(hw)) {
3836ab6bfe3SJack F Vogel DEBUGOUT("Required LANPHYPC toggle blocked by ME\n");
3847609433eSJack F Vogel ret_val = -E1000_ERR_PHY;
3856ab6bfe3SJack F Vogel break;
3866ab6bfe3SJack F Vogel }
3876ab6bfe3SJack F Vogel
3887609433eSJack F Vogel /* Toggle LANPHYPC Value bit */
3897609433eSJack F Vogel e1000_toggle_lanphypc_pch_lpt(hw);
3907609433eSJack F Vogel if (hw->mac.type >= e1000_pch_lpt) {
3917609433eSJack F Vogel if (e1000_phy_is_accessible_pchlan(hw))
3927609433eSJack F Vogel break;
3936ab6bfe3SJack F Vogel
3946ab6bfe3SJack F Vogel /* Toggling LANPHYPC brings the PHY out of SMBus mode
3957609433eSJack F Vogel * so ensure that the MAC is also out of SMBus mode
3966ab6bfe3SJack F Vogel */
3976ab6bfe3SJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
3986ab6bfe3SJack F Vogel mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
3996ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
4006ab6bfe3SJack F Vogel
4017609433eSJack F Vogel if (e1000_phy_is_accessible_pchlan(hw))
4027609433eSJack F Vogel break;
4037609433eSJack F Vogel
4047609433eSJack F Vogel ret_val = -E1000_ERR_PHY;
4056ab6bfe3SJack F Vogel }
4066ab6bfe3SJack F Vogel break;
4076ab6bfe3SJack F Vogel default:
4086ab6bfe3SJack F Vogel break;
4096ab6bfe3SJack F Vogel }
4106ab6bfe3SJack F Vogel
4116ab6bfe3SJack F Vogel hw->phy.ops.release(hw);
4127609433eSJack F Vogel if (!ret_val) {
4137609433eSJack F Vogel
4147609433eSJack F Vogel /* Check to see if able to reset PHY. Print error if not */
4157609433eSJack F Vogel if (hw->phy.ops.check_reset_block(hw)) {
4167609433eSJack F Vogel ERROR_REPORT("Reset blocked by ME\n");
4177609433eSJack F Vogel goto out;
4187609433eSJack F Vogel }
4196ab6bfe3SJack F Vogel
4206ab6bfe3SJack F Vogel /* Reset the PHY before any access to it. Doing so, ensures
4216ab6bfe3SJack F Vogel * that the PHY is in a known good state before we read/write
4226ab6bfe3SJack F Vogel * PHY registers. The generic reset is sufficient here,
4236ab6bfe3SJack F Vogel * because we haven't determined the PHY type yet.
4246ab6bfe3SJack F Vogel */
4256ab6bfe3SJack F Vogel ret_val = e1000_phy_hw_reset_generic(hw);
4267609433eSJack F Vogel if (ret_val)
4277609433eSJack F Vogel goto out;
4287609433eSJack F Vogel
4297609433eSJack F Vogel /* On a successful reset, possibly need to wait for the PHY
4307609433eSJack F Vogel * to quiesce to an accessible state before returning control
4317609433eSJack F Vogel * to the calling function. If the PHY does not quiesce, then
4327609433eSJack F Vogel * return E1000E_BLK_PHY_RESET, as this is the condition that
4337609433eSJack F Vogel * the PHY is in.
4347609433eSJack F Vogel */
4357609433eSJack F Vogel ret_val = hw->phy.ops.check_reset_block(hw);
4367609433eSJack F Vogel if (ret_val)
4377609433eSJack F Vogel ERROR_REPORT("ME blocked access to PHY after reset\n");
4387609433eSJack F Vogel }
4396ab6bfe3SJack F Vogel
4406ab6bfe3SJack F Vogel out:
4416ab6bfe3SJack F Vogel /* Ungate automatic PHY configuration on non-managed 82579 */
4426ab6bfe3SJack F Vogel if ((hw->mac.type == e1000_pch2lan) &&
4436ab6bfe3SJack F Vogel !(fwsm & E1000_ICH_FWSM_FW_VALID)) {
4446ab6bfe3SJack F Vogel msec_delay(10);
4451bbdc25fSKevin Bowling e1000_gate_hw_phy_config_ich8lan(hw, false);
4466ab6bfe3SJack F Vogel }
4476ab6bfe3SJack F Vogel
4486ab6bfe3SJack F Vogel return ret_val;
4494dab5c37SJack F Vogel }
4504dab5c37SJack F Vogel
4518cfa0ad2SJack F Vogel /**
4529d81738fSJack F Vogel * e1000_init_phy_params_pchlan - Initialize PHY function pointers
4539d81738fSJack F Vogel * @hw: pointer to the HW structure
4549d81738fSJack F Vogel *
4559d81738fSJack F Vogel * Initialize family-specific PHY parameters and function pointers.
4569d81738fSJack F Vogel **/
e1000_init_phy_params_pchlan(struct e1000_hw * hw)4579d81738fSJack F Vogel static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
4589d81738fSJack F Vogel {
4599d81738fSJack F Vogel struct e1000_phy_info *phy = &hw->phy;
4606ab6bfe3SJack F Vogel s32 ret_val;
4619d81738fSJack F Vogel
4629d81738fSJack F Vogel DEBUGFUNC("e1000_init_phy_params_pchlan");
4639d81738fSJack F Vogel
4649d81738fSJack F Vogel phy->addr = 1;
4659d81738fSJack F Vogel phy->reset_delay_us = 100;
4669d81738fSJack F Vogel
4679d81738fSJack F Vogel phy->ops.acquire = e1000_acquire_swflag_ich8lan;
4689d81738fSJack F Vogel phy->ops.check_reset_block = e1000_check_reset_block_ich8lan;
4699d81738fSJack F Vogel phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan;
4704dab5c37SJack F Vogel phy->ops.set_page = e1000_set_page_igp;
4719d81738fSJack F Vogel phy->ops.read_reg = e1000_read_phy_reg_hv;
4724edd8523SJack F Vogel phy->ops.read_reg_locked = e1000_read_phy_reg_hv_locked;
4734dab5c37SJack F Vogel phy->ops.read_reg_page = e1000_read_phy_reg_page_hv;
4749d81738fSJack F Vogel phy->ops.release = e1000_release_swflag_ich8lan;
4759d81738fSJack F Vogel phy->ops.reset = e1000_phy_hw_reset_ich8lan;
4764edd8523SJack F Vogel phy->ops.set_d0_lplu_state = e1000_set_lplu_state_pchlan;
4774edd8523SJack F Vogel phy->ops.set_d3_lplu_state = e1000_set_lplu_state_pchlan;
4789d81738fSJack F Vogel phy->ops.write_reg = e1000_write_phy_reg_hv;
4794edd8523SJack F Vogel phy->ops.write_reg_locked = e1000_write_phy_reg_hv_locked;
4804dab5c37SJack F Vogel phy->ops.write_reg_page = e1000_write_phy_reg_page_hv;
4819d81738fSJack F Vogel phy->ops.power_up = e1000_power_up_phy_copper;
4829d81738fSJack F Vogel phy->ops.power_down = e1000_power_down_phy_copper_ich8lan;
4839d81738fSJack F Vogel phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
4849d81738fSJack F Vogel
4859d81738fSJack F Vogel phy->id = e1000_phy_unknown;
4866ab6bfe3SJack F Vogel
4876ab6bfe3SJack F Vogel ret_val = e1000_init_phy_workarounds_pchlan(hw);
4886ab6bfe3SJack F Vogel if (ret_val)
4896ab6bfe3SJack F Vogel return ret_val;
4906ab6bfe3SJack F Vogel
4916ab6bfe3SJack F Vogel if (phy->id == e1000_phy_unknown)
4927d9119bdSJack F Vogel switch (hw->mac.type) {
4937d9119bdSJack F Vogel default:
494a69ed8dfSJack F Vogel ret_val = e1000_get_phy_id(hw);
495a69ed8dfSJack F Vogel if (ret_val)
4966ab6bfe3SJack F Vogel return ret_val;
4977d9119bdSJack F Vogel if ((phy->id != 0) && (phy->id != PHY_REVISION_MASK))
4987d9119bdSJack F Vogel break;
499e05d9788SKevin Bowling /* FALLTHROUGH */
5007d9119bdSJack F Vogel case e1000_pch2lan:
5016ab6bfe3SJack F Vogel case e1000_pch_lpt:
502c80429ceSEric Joyner case e1000_pch_spt:
5036fe4c0a0SSean Bruno case e1000_pch_cnp:
50459690eabSKevin Bowling case e1000_pch_tgp:
50559690eabSKevin Bowling case e1000_pch_adp:
50659690eabSKevin Bowling case e1000_pch_mtp:
507*905ae588SKevin Bowling case e1000_pch_ptp:
5086ab6bfe3SJack F Vogel /* In case the PHY needs to be in mdio slow mode,
509a69ed8dfSJack F Vogel * set slow mode and try to get the PHY id again.
510a69ed8dfSJack F Vogel */
511a69ed8dfSJack F Vogel ret_val = e1000_set_mdio_slow_mode_hv(hw);
512a69ed8dfSJack F Vogel if (ret_val)
5136ab6bfe3SJack F Vogel return ret_val;
514a69ed8dfSJack F Vogel ret_val = e1000_get_phy_id(hw);
515a69ed8dfSJack F Vogel if (ret_val)
5166ab6bfe3SJack F Vogel return ret_val;
5177d9119bdSJack F Vogel break;
518a69ed8dfSJack F Vogel }
5199d81738fSJack F Vogel phy->type = e1000_get_phy_type_from_id(phy->id);
5209d81738fSJack F Vogel
5214edd8523SJack F Vogel switch (phy->type) {
5224edd8523SJack F Vogel case e1000_phy_82577:
5237d9119bdSJack F Vogel case e1000_phy_82579:
5246ab6bfe3SJack F Vogel case e1000_phy_i217:
5259d81738fSJack F Vogel phy->ops.check_polarity = e1000_check_polarity_82577;
5269d81738fSJack F Vogel phy->ops.force_speed_duplex =
5279d81738fSJack F Vogel e1000_phy_force_speed_duplex_82577;
5289d81738fSJack F Vogel phy->ops.get_cable_length = e1000_get_cable_length_82577;
5299d81738fSJack F Vogel phy->ops.get_info = e1000_get_phy_info_82577;
5309d81738fSJack F Vogel phy->ops.commit = e1000_phy_sw_reset_generic;
5318ec87fc5SJack F Vogel break;
5324edd8523SJack F Vogel case e1000_phy_82578:
5334edd8523SJack F Vogel phy->ops.check_polarity = e1000_check_polarity_m88;
5344edd8523SJack F Vogel phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
5354edd8523SJack F Vogel phy->ops.get_cable_length = e1000_get_cable_length_m88;
5364edd8523SJack F Vogel phy->ops.get_info = e1000_get_phy_info_m88;
5374edd8523SJack F Vogel break;
5384edd8523SJack F Vogel default:
5394edd8523SJack F Vogel ret_val = -E1000_ERR_PHY;
5404edd8523SJack F Vogel break;
5419d81738fSJack F Vogel }
5429d81738fSJack F Vogel
5439d81738fSJack F Vogel return ret_val;
5449d81738fSJack F Vogel }
5459d81738fSJack F Vogel
5469d81738fSJack F Vogel /**
5478cfa0ad2SJack F Vogel * e1000_init_phy_params_ich8lan - Initialize PHY function pointers
5488cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
5498cfa0ad2SJack F Vogel *
5508cfa0ad2SJack F Vogel * Initialize family-specific PHY parameters and function pointers.
5518cfa0ad2SJack F Vogel **/
e1000_init_phy_params_ich8lan(struct e1000_hw * hw)5528cfa0ad2SJack F Vogel static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
5538cfa0ad2SJack F Vogel {
5548cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy;
5556ab6bfe3SJack F Vogel s32 ret_val;
5568cfa0ad2SJack F Vogel u16 i = 0;
5578cfa0ad2SJack F Vogel
5588cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_phy_params_ich8lan");
5598cfa0ad2SJack F Vogel
5608cfa0ad2SJack F Vogel phy->addr = 1;
5618cfa0ad2SJack F Vogel phy->reset_delay_us = 100;
5628cfa0ad2SJack F Vogel
5638cfa0ad2SJack F Vogel phy->ops.acquire = e1000_acquire_swflag_ich8lan;
5648cfa0ad2SJack F Vogel phy->ops.check_reset_block = e1000_check_reset_block_ich8lan;
5658cfa0ad2SJack F Vogel phy->ops.get_cable_length = e1000_get_cable_length_igp_2;
5668cfa0ad2SJack F Vogel phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan;
5678cfa0ad2SJack F Vogel phy->ops.read_reg = e1000_read_phy_reg_igp;
5688cfa0ad2SJack F Vogel phy->ops.release = e1000_release_swflag_ich8lan;
5698cfa0ad2SJack F Vogel phy->ops.reset = e1000_phy_hw_reset_ich8lan;
5708cfa0ad2SJack F Vogel phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan;
5718cfa0ad2SJack F Vogel phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan;
5728cfa0ad2SJack F Vogel phy->ops.write_reg = e1000_write_phy_reg_igp;
5738cfa0ad2SJack F Vogel phy->ops.power_up = e1000_power_up_phy_copper;
5748cfa0ad2SJack F Vogel phy->ops.power_down = e1000_power_down_phy_copper_ich8lan;
5758cfa0ad2SJack F Vogel
5766ab6bfe3SJack F Vogel /* We may need to do this twice - once for IGP and if that fails,
5778cfa0ad2SJack F Vogel * we'll set BM func pointers and try again
5788cfa0ad2SJack F Vogel */
5798cfa0ad2SJack F Vogel ret_val = e1000_determine_phy_address(hw);
5808cfa0ad2SJack F Vogel if (ret_val) {
5818cfa0ad2SJack F Vogel phy->ops.write_reg = e1000_write_phy_reg_bm;
5828cfa0ad2SJack F Vogel phy->ops.read_reg = e1000_read_phy_reg_bm;
5838cfa0ad2SJack F Vogel ret_val = e1000_determine_phy_address(hw);
5848cfa0ad2SJack F Vogel if (ret_val) {
585d035aa2dSJack F Vogel DEBUGOUT("Cannot determine PHY addr. Erroring out\n");
5866ab6bfe3SJack F Vogel return ret_val;
5878cfa0ad2SJack F Vogel }
5888cfa0ad2SJack F Vogel }
5898cfa0ad2SJack F Vogel
5908cfa0ad2SJack F Vogel phy->id = 0;
5918cfa0ad2SJack F Vogel while ((e1000_phy_unknown == e1000_get_phy_type_from_id(phy->id)) &&
5928cfa0ad2SJack F Vogel (i++ < 100)) {
5938cfa0ad2SJack F Vogel msec_delay(1);
5948cfa0ad2SJack F Vogel ret_val = e1000_get_phy_id(hw);
5958cfa0ad2SJack F Vogel if (ret_val)
5966ab6bfe3SJack F Vogel return ret_val;
5978cfa0ad2SJack F Vogel }
5988cfa0ad2SJack F Vogel
5998cfa0ad2SJack F Vogel /* Verify phy id */
6008cfa0ad2SJack F Vogel switch (phy->id) {
6018cfa0ad2SJack F Vogel case IGP03E1000_E_PHY_ID:
6028cfa0ad2SJack F Vogel phy->type = e1000_phy_igp_3;
6038cfa0ad2SJack F Vogel phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
6044edd8523SJack F Vogel phy->ops.read_reg_locked = e1000_read_phy_reg_igp_locked;
6054edd8523SJack F Vogel phy->ops.write_reg_locked = e1000_write_phy_reg_igp_locked;
6064edd8523SJack F Vogel phy->ops.get_info = e1000_get_phy_info_igp;
6074edd8523SJack F Vogel phy->ops.check_polarity = e1000_check_polarity_igp;
6084edd8523SJack F Vogel phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp;
6098cfa0ad2SJack F Vogel break;
6108cfa0ad2SJack F Vogel case IFE_E_PHY_ID:
6118cfa0ad2SJack F Vogel case IFE_PLUS_E_PHY_ID:
6128cfa0ad2SJack F Vogel case IFE_C_E_PHY_ID:
6138cfa0ad2SJack F Vogel phy->type = e1000_phy_ife;
6148cfa0ad2SJack F Vogel phy->autoneg_mask = E1000_ALL_NOT_GIG;
6154edd8523SJack F Vogel phy->ops.get_info = e1000_get_phy_info_ife;
6164edd8523SJack F Vogel phy->ops.check_polarity = e1000_check_polarity_ife;
6174edd8523SJack F Vogel phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife;
6188cfa0ad2SJack F Vogel break;
6198cfa0ad2SJack F Vogel case BME1000_E_PHY_ID:
6208cfa0ad2SJack F Vogel phy->type = e1000_phy_bm;
6218cfa0ad2SJack F Vogel phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
6228cfa0ad2SJack F Vogel phy->ops.read_reg = e1000_read_phy_reg_bm;
6238cfa0ad2SJack F Vogel phy->ops.write_reg = e1000_write_phy_reg_bm;
6248cfa0ad2SJack F Vogel phy->ops.commit = e1000_phy_sw_reset_generic;
6254edd8523SJack F Vogel phy->ops.get_info = e1000_get_phy_info_m88;
6264edd8523SJack F Vogel phy->ops.check_polarity = e1000_check_polarity_m88;
6274edd8523SJack F Vogel phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
6288cfa0ad2SJack F Vogel break;
6298cfa0ad2SJack F Vogel default:
6306ab6bfe3SJack F Vogel return -E1000_ERR_PHY;
6316ab6bfe3SJack F Vogel break;
6328cfa0ad2SJack F Vogel }
6338cfa0ad2SJack F Vogel
6346ab6bfe3SJack F Vogel return E1000_SUCCESS;
6358cfa0ad2SJack F Vogel }
6368cfa0ad2SJack F Vogel
6378cfa0ad2SJack F Vogel /**
6388cfa0ad2SJack F Vogel * e1000_init_nvm_params_ich8lan - Initialize NVM function pointers
6398cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
6408cfa0ad2SJack F Vogel *
6418cfa0ad2SJack F Vogel * Initialize family-specific NVM parameters and function
6428cfa0ad2SJack F Vogel * pointers.
6438cfa0ad2SJack F Vogel **/
e1000_init_nvm_params_ich8lan(struct e1000_hw * hw)6448cfa0ad2SJack F Vogel static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
6458cfa0ad2SJack F Vogel {
6468cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm;
647daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
6488cfa0ad2SJack F Vogel u32 gfpreg, sector_base_addr, sector_end_addr;
6498cfa0ad2SJack F Vogel u16 i;
650c80429ceSEric Joyner u32 nvm_size;
6518cfa0ad2SJack F Vogel
6528cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_nvm_params_ich8lan");
6538cfa0ad2SJack F Vogel
6548cc64f1eSJack F Vogel nvm->type = e1000_nvm_flash_sw;
655c80429ceSEric Joyner
656295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt) {
657c80429ceSEric Joyner /* in SPT, gfpreg doesn't exist. NVM size is taken from the
658c80429ceSEric Joyner * STRAP register. This is because in SPT the GbE Flash region
659c80429ceSEric Joyner * is no longer accessed through the flash registers. Instead,
660c80429ceSEric Joyner * the mechanism has changed, and the Flash region access
661c80429ceSEric Joyner * registers are now implemented in GbE memory space.
662c80429ceSEric Joyner */
663c80429ceSEric Joyner nvm->flash_base_addr = 0;
664c80429ceSEric Joyner nvm_size =
665c80429ceSEric Joyner (((E1000_READ_REG(hw, E1000_STRAP) >> 1) & 0x1F) + 1)
666c80429ceSEric Joyner * NVM_SIZE_MULTIPLIER;
667c80429ceSEric Joyner nvm->flash_bank_size = nvm_size / 2;
668c80429ceSEric Joyner /* Adjust to word count */
669c80429ceSEric Joyner nvm->flash_bank_size /= sizeof(u16);
670c80429ceSEric Joyner /* Set the base address for flash register access */
671c80429ceSEric Joyner hw->flash_address = hw->hw_addr + E1000_FLASH_BASE_ADDR;
672c80429ceSEric Joyner } else {
673c80429ceSEric Joyner /* Can't read flash registers if register set isn't mapped. */
6748cfa0ad2SJack F Vogel if (!hw->flash_address) {
6758cfa0ad2SJack F Vogel DEBUGOUT("ERROR: Flash registers not mapped\n");
6766ab6bfe3SJack F Vogel return -E1000_ERR_CONFIG;
6778cfa0ad2SJack F Vogel }
6788cfa0ad2SJack F Vogel
6798cfa0ad2SJack F Vogel gfpreg = E1000_READ_FLASH_REG(hw, ICH_FLASH_GFPREG);
6808cfa0ad2SJack F Vogel
6816ab6bfe3SJack F Vogel /* sector_X_addr is a "sector"-aligned address (4096 bytes)
6828cfa0ad2SJack F Vogel * Add 1 to sector_end_addr since this sector is included in
6838cfa0ad2SJack F Vogel * the overall size.
6848cfa0ad2SJack F Vogel */
6858cfa0ad2SJack F Vogel sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
6868cfa0ad2SJack F Vogel sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1;
6878cfa0ad2SJack F Vogel
6888cfa0ad2SJack F Vogel /* flash_base_addr is byte-aligned */
689c80429ceSEric Joyner nvm->flash_base_addr = sector_base_addr
690c80429ceSEric Joyner << FLASH_SECTOR_ADDR_SHIFT;
6918cfa0ad2SJack F Vogel
6926ab6bfe3SJack F Vogel /* find total size of the NVM, then cut in half since the total
6938cfa0ad2SJack F Vogel * size represents two separate NVM banks.
6948cfa0ad2SJack F Vogel */
6957609433eSJack F Vogel nvm->flash_bank_size = ((sector_end_addr - sector_base_addr)
6967609433eSJack F Vogel << FLASH_SECTOR_ADDR_SHIFT);
6978cfa0ad2SJack F Vogel nvm->flash_bank_size /= 2;
6988cfa0ad2SJack F Vogel /* Adjust to word count */
6998cfa0ad2SJack F Vogel nvm->flash_bank_size /= sizeof(u16);
700c80429ceSEric Joyner }
7018cfa0ad2SJack F Vogel
7028cfa0ad2SJack F Vogel nvm->word_size = E1000_SHADOW_RAM_WORDS;
7038cfa0ad2SJack F Vogel
7048cfa0ad2SJack F Vogel /* Clear shadow ram */
7058cfa0ad2SJack F Vogel for (i = 0; i < nvm->word_size; i++) {
7061bbdc25fSKevin Bowling dev_spec->shadow_ram[i].modified = false;
7078cfa0ad2SJack F Vogel dev_spec->shadow_ram[i].value = 0xFFFF;
7088cfa0ad2SJack F Vogel }
7098cfa0ad2SJack F Vogel
7108cfa0ad2SJack F Vogel /* Function Pointers */
7114edd8523SJack F Vogel nvm->ops.acquire = e1000_acquire_nvm_ich8lan;
7124edd8523SJack F Vogel nvm->ops.release = e1000_release_nvm_ich8lan;
713295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt) {
714c80429ceSEric Joyner nvm->ops.read = e1000_read_nvm_spt;
715c80429ceSEric Joyner nvm->ops.update = e1000_update_nvm_checksum_spt;
716c80429ceSEric Joyner } else {
7178cfa0ad2SJack F Vogel nvm->ops.read = e1000_read_nvm_ich8lan;
7188cfa0ad2SJack F Vogel nvm->ops.update = e1000_update_nvm_checksum_ich8lan;
719c80429ceSEric Joyner }
7208cfa0ad2SJack F Vogel nvm->ops.valid_led_default = e1000_valid_led_default_ich8lan;
7218cfa0ad2SJack F Vogel nvm->ops.validate = e1000_validate_nvm_checksum_ich8lan;
7228cfa0ad2SJack F Vogel nvm->ops.write = e1000_write_nvm_ich8lan;
7238cfa0ad2SJack F Vogel
7246ab6bfe3SJack F Vogel return E1000_SUCCESS;
7258cfa0ad2SJack F Vogel }
7268cfa0ad2SJack F Vogel
7278cfa0ad2SJack F Vogel /**
7288cfa0ad2SJack F Vogel * e1000_init_mac_params_ich8lan - Initialize MAC function pointers
7298cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
7308cfa0ad2SJack F Vogel *
7318cfa0ad2SJack F Vogel * Initialize family-specific MAC parameters and function
7328cfa0ad2SJack F Vogel * pointers.
7338cfa0ad2SJack F Vogel **/
e1000_init_mac_params_ich8lan(struct e1000_hw * hw)7348cfa0ad2SJack F Vogel static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
7358cfa0ad2SJack F Vogel {
7368cfa0ad2SJack F Vogel struct e1000_mac_info *mac = &hw->mac;
7378cfa0ad2SJack F Vogel
7388cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_mac_params_ich8lan");
7398cfa0ad2SJack F Vogel
7408cfa0ad2SJack F Vogel /* Set media type function pointer */
7418cfa0ad2SJack F Vogel hw->phy.media_type = e1000_media_type_copper;
7428cfa0ad2SJack F Vogel
7438cfa0ad2SJack F Vogel /* Set mta register count */
7448cfa0ad2SJack F Vogel mac->mta_reg_count = 32;
7458cfa0ad2SJack F Vogel /* Set rar entry count */
7468cfa0ad2SJack F Vogel mac->rar_entry_count = E1000_ICH_RAR_ENTRIES;
7478cfa0ad2SJack F Vogel if (mac->type == e1000_ich8lan)
7488cfa0ad2SJack F Vogel mac->rar_entry_count--;
7498cfa0ad2SJack F Vogel /* Set if part includes ASF firmware */
7501bbdc25fSKevin Bowling mac->asf_firmware_present = true;
7518ec87fc5SJack F Vogel /* FWSM register */
7521bbdc25fSKevin Bowling mac->has_fwsm = true;
7538ec87fc5SJack F Vogel /* ARC subsystem not supported */
7541bbdc25fSKevin Bowling mac->arc_subsystem_valid = false;
7554edd8523SJack F Vogel /* Adaptive IFS supported */
7561bbdc25fSKevin Bowling mac->adaptive_ifs = true;
7578cfa0ad2SJack F Vogel
7588cfa0ad2SJack F Vogel /* Function pointers */
7598cfa0ad2SJack F Vogel
7608cfa0ad2SJack F Vogel /* bus type/speed/width */
7618cfa0ad2SJack F Vogel mac->ops.get_bus_info = e1000_get_bus_info_ich8lan;
762daf9197cSJack F Vogel /* function id */
763daf9197cSJack F Vogel mac->ops.set_lan_id = e1000_set_lan_id_single_port;
7648cfa0ad2SJack F Vogel /* reset */
7658cfa0ad2SJack F Vogel mac->ops.reset_hw = e1000_reset_hw_ich8lan;
7668cfa0ad2SJack F Vogel /* hw initialization */
7678cfa0ad2SJack F Vogel mac->ops.init_hw = e1000_init_hw_ich8lan;
7688cfa0ad2SJack F Vogel /* link setup */
7698cfa0ad2SJack F Vogel mac->ops.setup_link = e1000_setup_link_ich8lan;
7708cfa0ad2SJack F Vogel /* physical interface setup */
7718cfa0ad2SJack F Vogel mac->ops.setup_physical_interface = e1000_setup_copper_link_ich8lan;
7728cfa0ad2SJack F Vogel /* check for link */
7734edd8523SJack F Vogel mac->ops.check_for_link = e1000_check_for_copper_link_ich8lan;
7748cfa0ad2SJack F Vogel /* link info */
7758cfa0ad2SJack F Vogel mac->ops.get_link_up_info = e1000_get_link_up_info_ich8lan;
7768cfa0ad2SJack F Vogel /* multicast address update */
7778cfa0ad2SJack F Vogel mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
778d035aa2dSJack F Vogel /* clear hardware counters */
779d035aa2dSJack F Vogel mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan;
780d035aa2dSJack F Vogel
7816ab6bfe3SJack F Vogel /* LED and other operations */
782d035aa2dSJack F Vogel switch (mac->type) {
783d035aa2dSJack F Vogel case e1000_ich8lan:
784d035aa2dSJack F Vogel case e1000_ich9lan:
785d035aa2dSJack F Vogel case e1000_ich10lan:
7867d9119bdSJack F Vogel /* check management mode */
7877d9119bdSJack F Vogel mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan;
788d035aa2dSJack F Vogel /* ID LED init */
789d035aa2dSJack F Vogel mac->ops.id_led_init = e1000_id_led_init_generic;
7908cfa0ad2SJack F Vogel /* blink LED */
7918cfa0ad2SJack F Vogel mac->ops.blink_led = e1000_blink_led_generic;
7928cfa0ad2SJack F Vogel /* setup LED */
7938cfa0ad2SJack F Vogel mac->ops.setup_led = e1000_setup_led_generic;
7948cfa0ad2SJack F Vogel /* cleanup LED */
7958cfa0ad2SJack F Vogel mac->ops.cleanup_led = e1000_cleanup_led_ich8lan;
7968cfa0ad2SJack F Vogel /* turn on/off LED */
7978cfa0ad2SJack F Vogel mac->ops.led_on = e1000_led_on_ich8lan;
7988cfa0ad2SJack F Vogel mac->ops.led_off = e1000_led_off_ich8lan;
799d035aa2dSJack F Vogel break;
8007d9119bdSJack F Vogel case e1000_pch2lan:
8017d9119bdSJack F Vogel mac->rar_entry_count = E1000_PCH2_RAR_ENTRIES;
8027d9119bdSJack F Vogel mac->ops.rar_set = e1000_rar_set_pch2lan;
803e05d9788SKevin Bowling /* FALLTHROUGH */
8046ab6bfe3SJack F Vogel case e1000_pch_lpt:
805c80429ceSEric Joyner case e1000_pch_spt:
8066fe4c0a0SSean Bruno case e1000_pch_cnp:
80759690eabSKevin Bowling case e1000_pch_tgp:
80859690eabSKevin Bowling case e1000_pch_adp:
80959690eabSKevin Bowling case e1000_pch_mtp:
810*905ae588SKevin Bowling case e1000_pch_ptp:
811730d3130SJack F Vogel /* multicast address update for pch2 */
812730d3130SJack F Vogel mac->ops.update_mc_addr_list =
813730d3130SJack F Vogel e1000_update_mc_addr_list_pch2lan;
814e05d9788SKevin Bowling /* FALLTHROUGH */
8159d81738fSJack F Vogel case e1000_pchlan:
8167d9119bdSJack F Vogel /* check management mode */
8177d9119bdSJack F Vogel mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan;
8189d81738fSJack F Vogel /* ID LED init */
8199d81738fSJack F Vogel mac->ops.id_led_init = e1000_id_led_init_pchlan;
8209d81738fSJack F Vogel /* setup LED */
8219d81738fSJack F Vogel mac->ops.setup_led = e1000_setup_led_pchlan;
8229d81738fSJack F Vogel /* cleanup LED */
8239d81738fSJack F Vogel mac->ops.cleanup_led = e1000_cleanup_led_pchlan;
8249d81738fSJack F Vogel /* turn on/off LED */
8259d81738fSJack F Vogel mac->ops.led_on = e1000_led_on_pchlan;
8269d81738fSJack F Vogel mac->ops.led_off = e1000_led_off_pchlan;
8279d81738fSJack F Vogel break;
828d035aa2dSJack F Vogel default:
829d035aa2dSJack F Vogel break;
830d035aa2dSJack F Vogel }
8318cfa0ad2SJack F Vogel
832295df609SEric Joyner if (mac->type >= e1000_pch_lpt) {
8336ab6bfe3SJack F Vogel mac->rar_entry_count = E1000_PCH_LPT_RAR_ENTRIES;
8346ab6bfe3SJack F Vogel mac->ops.rar_set = e1000_rar_set_pch_lpt;
8356ab6bfe3SJack F Vogel mac->ops.setup_physical_interface = e1000_setup_copper_link_pch_lpt;
836e373323fSSean Bruno mac->ops.set_obff_timer = e1000_set_obff_timer_pch_lpt;
8374dab5c37SJack F Vogel }
8384dab5c37SJack F Vogel
8398cfa0ad2SJack F Vogel /* Enable PCS Lock-loss workaround for ICH8 */
8408cfa0ad2SJack F Vogel if (mac->type == e1000_ich8lan)
8411bbdc25fSKevin Bowling e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, true);
8428cfa0ad2SJack F Vogel
843daf9197cSJack F Vogel return E1000_SUCCESS;
8448cfa0ad2SJack F Vogel }
8458cfa0ad2SJack F Vogel
8468cfa0ad2SJack F Vogel /**
8476ab6bfe3SJack F Vogel * __e1000_access_emi_reg_locked - Read/write EMI register
8486ab6bfe3SJack F Vogel * @hw: pointer to the HW structure
8496c59e186SGuinan Sun * @address: EMI address to program
8506ab6bfe3SJack F Vogel * @data: pointer to value to read/write from/to the EMI address
8516ab6bfe3SJack F Vogel * @read: boolean flag to indicate read or write
8526ab6bfe3SJack F Vogel *
8536ab6bfe3SJack F Vogel * This helper function assumes the SW/FW/HW Semaphore is already acquired.
8546ab6bfe3SJack F Vogel **/
__e1000_access_emi_reg_locked(struct e1000_hw * hw,u16 address,u16 * data,bool read)8556ab6bfe3SJack F Vogel static s32 __e1000_access_emi_reg_locked(struct e1000_hw *hw, u16 address,
8566ab6bfe3SJack F Vogel u16 *data, bool read)
8576ab6bfe3SJack F Vogel {
8586ab6bfe3SJack F Vogel s32 ret_val;
8596ab6bfe3SJack F Vogel
8606ab6bfe3SJack F Vogel DEBUGFUNC("__e1000_access_emi_reg_locked");
8616ab6bfe3SJack F Vogel
8626ab6bfe3SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_ADDR, address);
8636ab6bfe3SJack F Vogel if (ret_val)
8646ab6bfe3SJack F Vogel return ret_val;
8656ab6bfe3SJack F Vogel
8666ab6bfe3SJack F Vogel if (read)
8676ab6bfe3SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, I82579_EMI_DATA,
8686ab6bfe3SJack F Vogel data);
8696ab6bfe3SJack F Vogel else
8706ab6bfe3SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_DATA,
8716ab6bfe3SJack F Vogel *data);
8726ab6bfe3SJack F Vogel
8736ab6bfe3SJack F Vogel return ret_val;
8746ab6bfe3SJack F Vogel }
8756ab6bfe3SJack F Vogel
8766ab6bfe3SJack F Vogel /**
8776ab6bfe3SJack F Vogel * e1000_read_emi_reg_locked - Read Extended Management Interface register
8786ab6bfe3SJack F Vogel * @hw: pointer to the HW structure
8796ab6bfe3SJack F Vogel * @addr: EMI address to program
8806ab6bfe3SJack F Vogel * @data: value to be read from the EMI address
8816ab6bfe3SJack F Vogel *
8826ab6bfe3SJack F Vogel * Assumes the SW/FW/HW Semaphore is already acquired.
8836ab6bfe3SJack F Vogel **/
e1000_read_emi_reg_locked(struct e1000_hw * hw,u16 addr,u16 * data)8846ab6bfe3SJack F Vogel s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data)
8856ab6bfe3SJack F Vogel {
8866ab6bfe3SJack F Vogel DEBUGFUNC("e1000_read_emi_reg_locked");
8876ab6bfe3SJack F Vogel
8881bbdc25fSKevin Bowling return __e1000_access_emi_reg_locked(hw, addr, data, true);
8896ab6bfe3SJack F Vogel }
8906ab6bfe3SJack F Vogel
8916ab6bfe3SJack F Vogel /**
8926ab6bfe3SJack F Vogel * e1000_write_emi_reg_locked - Write Extended Management Interface register
8936ab6bfe3SJack F Vogel * @hw: pointer to the HW structure
8946ab6bfe3SJack F Vogel * @addr: EMI address to program
8956ab6bfe3SJack F Vogel * @data: value to be written to the EMI address
8966ab6bfe3SJack F Vogel *
8976ab6bfe3SJack F Vogel * Assumes the SW/FW/HW Semaphore is already acquired.
8986ab6bfe3SJack F Vogel **/
e1000_write_emi_reg_locked(struct e1000_hw * hw,u16 addr,u16 data)8997609433eSJack F Vogel s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data)
9006ab6bfe3SJack F Vogel {
9016ab6bfe3SJack F Vogel DEBUGFUNC("e1000_read_emi_reg_locked");
9026ab6bfe3SJack F Vogel
9031bbdc25fSKevin Bowling return __e1000_access_emi_reg_locked(hw, addr, &data, false);
9046ab6bfe3SJack F Vogel }
9056ab6bfe3SJack F Vogel
9066ab6bfe3SJack F Vogel /**
9077d9119bdSJack F Vogel * e1000_set_eee_pchlan - Enable/disable EEE support
9087d9119bdSJack F Vogel * @hw: pointer to the HW structure
9097d9119bdSJack F Vogel *
9106ab6bfe3SJack F Vogel * Enable/disable EEE based on setting in dev_spec structure, the duplex of
9116ab6bfe3SJack F Vogel * the link and the EEE capabilities of the link partner. The LPI Control
9126ab6bfe3SJack F Vogel * register bits will remain set only if/when link is up.
9137609433eSJack F Vogel *
9147609433eSJack F Vogel * EEE LPI must not be asserted earlier than one second after link is up.
9157609433eSJack F Vogel * On 82579, EEE LPI should not be enabled until such time otherwise there
9167609433eSJack F Vogel * can be link issues with some switches. Other devices can have EEE LPI
9177609433eSJack F Vogel * enabled immediately upon link up since they have a timer in hardware which
9187609433eSJack F Vogel * prevents LPI from being asserted too early.
9197d9119bdSJack F Vogel **/
e1000_set_eee_pchlan(struct e1000_hw * hw)9207609433eSJack F Vogel s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
9217d9119bdSJack F Vogel {
9224dab5c37SJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
9236ab6bfe3SJack F Vogel s32 ret_val;
9247609433eSJack F Vogel u16 lpa, pcs_status, adv, adv_addr, lpi_ctrl, data;
9257d9119bdSJack F Vogel
9267d9119bdSJack F Vogel DEBUGFUNC("e1000_set_eee_pchlan");
9277d9119bdSJack F Vogel
9287609433eSJack F Vogel switch (hw->phy.type) {
9297609433eSJack F Vogel case e1000_phy_82579:
9307609433eSJack F Vogel lpa = I82579_EEE_LP_ABILITY;
9317609433eSJack F Vogel pcs_status = I82579_EEE_PCS_STATUS;
9327609433eSJack F Vogel adv_addr = I82579_EEE_ADVERTISEMENT;
9337609433eSJack F Vogel break;
9347609433eSJack F Vogel case e1000_phy_i217:
9357609433eSJack F Vogel lpa = I217_EEE_LP_ABILITY;
9367609433eSJack F Vogel pcs_status = I217_EEE_PCS_STATUS;
9377609433eSJack F Vogel adv_addr = I217_EEE_ADVERTISEMENT;
9387609433eSJack F Vogel break;
9397609433eSJack F Vogel default:
9406ab6bfe3SJack F Vogel return E1000_SUCCESS;
9417609433eSJack F Vogel }
9427d9119bdSJack F Vogel
9436ab6bfe3SJack F Vogel ret_val = hw->phy.ops.acquire(hw);
9447d9119bdSJack F Vogel if (ret_val)
9457d9119bdSJack F Vogel return ret_val;
9466ab6bfe3SJack F Vogel
9476ab6bfe3SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, I82579_LPI_CTRL, &lpi_ctrl);
9486ab6bfe3SJack F Vogel if (ret_val)
9496ab6bfe3SJack F Vogel goto release;
9506ab6bfe3SJack F Vogel
9516ab6bfe3SJack F Vogel /* Clear bits that enable EEE in various speeds */
9526ab6bfe3SJack F Vogel lpi_ctrl &= ~I82579_LPI_CTRL_ENABLE_MASK;
9536ab6bfe3SJack F Vogel
9546ab6bfe3SJack F Vogel /* Enable EEE if not disabled by user */
9556ab6bfe3SJack F Vogel if (!dev_spec->eee_disable) {
9566ab6bfe3SJack F Vogel /* Save off link partner's EEE ability */
9576ab6bfe3SJack F Vogel ret_val = e1000_read_emi_reg_locked(hw, lpa,
9586ab6bfe3SJack F Vogel &dev_spec->eee_lp_ability);
9596ab6bfe3SJack F Vogel if (ret_val)
9606ab6bfe3SJack F Vogel goto release;
9616ab6bfe3SJack F Vogel
9627609433eSJack F Vogel /* Read EEE advertisement */
9637609433eSJack F Vogel ret_val = e1000_read_emi_reg_locked(hw, adv_addr, &adv);
9647609433eSJack F Vogel if (ret_val)
9657609433eSJack F Vogel goto release;
9667609433eSJack F Vogel
9676ab6bfe3SJack F Vogel /* Enable EEE only for speeds in which the link partner is
9687609433eSJack F Vogel * EEE capable and for which we advertise EEE.
9696ab6bfe3SJack F Vogel */
9707609433eSJack F Vogel if (adv & dev_spec->eee_lp_ability & I82579_EEE_1000_SUPPORTED)
9716ab6bfe3SJack F Vogel lpi_ctrl |= I82579_LPI_CTRL_1000_ENABLE;
9726ab6bfe3SJack F Vogel
9737609433eSJack F Vogel if (adv & dev_spec->eee_lp_ability & I82579_EEE_100_SUPPORTED) {
9746ab6bfe3SJack F Vogel hw->phy.ops.read_reg_locked(hw, PHY_LP_ABILITY, &data);
9756ab6bfe3SJack F Vogel if (data & NWAY_LPAR_100TX_FD_CAPS)
9766ab6bfe3SJack F Vogel lpi_ctrl |= I82579_LPI_CTRL_100_ENABLE;
9776ab6bfe3SJack F Vogel else
9786ab6bfe3SJack F Vogel /* EEE is not supported in 100Half, so ignore
9796ab6bfe3SJack F Vogel * partner's EEE in 100 ability if full-duplex
9806ab6bfe3SJack F Vogel * is not advertised.
9816ab6bfe3SJack F Vogel */
9826ab6bfe3SJack F Vogel dev_spec->eee_lp_ability &=
9836ab6bfe3SJack F Vogel ~I82579_EEE_100_SUPPORTED;
9846ab6bfe3SJack F Vogel }
9857609433eSJack F Vogel }
9866ab6bfe3SJack F Vogel
9878cc64f1eSJack F Vogel if (hw->phy.type == e1000_phy_82579) {
9888cc64f1eSJack F Vogel ret_val = e1000_read_emi_reg_locked(hw, I82579_LPI_PLL_SHUT,
9898cc64f1eSJack F Vogel &data);
9908cc64f1eSJack F Vogel if (ret_val)
9918cc64f1eSJack F Vogel goto release;
9928cc64f1eSJack F Vogel
9938cc64f1eSJack F Vogel data &= ~I82579_LPI_100_PLL_SHUT;
9948cc64f1eSJack F Vogel ret_val = e1000_write_emi_reg_locked(hw, I82579_LPI_PLL_SHUT,
9958cc64f1eSJack F Vogel data);
9968cc64f1eSJack F Vogel }
9978cc64f1eSJack F Vogel
9986ab6bfe3SJack F Vogel /* R/Clr IEEE MMD 3.1 bits 11:10 - Tx/Rx LPI Received */
9996ab6bfe3SJack F Vogel ret_val = e1000_read_emi_reg_locked(hw, pcs_status, &data);
10006ab6bfe3SJack F Vogel if (ret_val)
10016ab6bfe3SJack F Vogel goto release;
10026ab6bfe3SJack F Vogel
10036ab6bfe3SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, I82579_LPI_CTRL, lpi_ctrl);
10046ab6bfe3SJack F Vogel release:
10056ab6bfe3SJack F Vogel hw->phy.ops.release(hw);
10066ab6bfe3SJack F Vogel
10076ab6bfe3SJack F Vogel return ret_val;
10086ab6bfe3SJack F Vogel }
10096ab6bfe3SJack F Vogel
10106ab6bfe3SJack F Vogel /**
10116ab6bfe3SJack F Vogel * e1000_k1_workaround_lpt_lp - K1 workaround on Lynxpoint-LP
10126ab6bfe3SJack F Vogel * @hw: pointer to the HW structure
10136ab6bfe3SJack F Vogel * @link: link up bool flag
10146ab6bfe3SJack F Vogel *
10156ab6bfe3SJack F Vogel * When K1 is enabled for 1Gbps, the MAC can miss 2 DMA completion indications
10166ab6bfe3SJack F Vogel * preventing further DMA write requests. Workaround the issue by disabling
10176ab6bfe3SJack F Vogel * the de-assertion of the clock request when in 1Gpbs mode.
10187609433eSJack F Vogel * Also, set appropriate Tx re-transmission timeouts for 10 and 100Half link
10197609433eSJack F Vogel * speeds in order to avoid Tx hangs.
10206ab6bfe3SJack F Vogel **/
e1000_k1_workaround_lpt_lp(struct e1000_hw * hw,bool link)10216ab6bfe3SJack F Vogel static s32 e1000_k1_workaround_lpt_lp(struct e1000_hw *hw, bool link)
10226ab6bfe3SJack F Vogel {
10236ab6bfe3SJack F Vogel u32 fextnvm6 = E1000_READ_REG(hw, E1000_FEXTNVM6);
10247609433eSJack F Vogel u32 status = E1000_READ_REG(hw, E1000_STATUS);
10256ab6bfe3SJack F Vogel s32 ret_val = E1000_SUCCESS;
10267609433eSJack F Vogel u16 reg;
10276ab6bfe3SJack F Vogel
10287609433eSJack F Vogel if (link && (status & E1000_STATUS_SPEED_1000)) {
10296ab6bfe3SJack F Vogel ret_val = hw->phy.ops.acquire(hw);
10306ab6bfe3SJack F Vogel if (ret_val)
10316ab6bfe3SJack F Vogel return ret_val;
10326ab6bfe3SJack F Vogel
10336ab6bfe3SJack F Vogel ret_val =
10346ab6bfe3SJack F Vogel e1000_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG,
10357609433eSJack F Vogel ®);
10366ab6bfe3SJack F Vogel if (ret_val)
10376ab6bfe3SJack F Vogel goto release;
10386ab6bfe3SJack F Vogel
10396ab6bfe3SJack F Vogel ret_val =
10406ab6bfe3SJack F Vogel e1000_write_kmrn_reg_locked(hw,
10416ab6bfe3SJack F Vogel E1000_KMRNCTRLSTA_K1_CONFIG,
10427609433eSJack F Vogel reg &
10436ab6bfe3SJack F Vogel ~E1000_KMRNCTRLSTA_K1_ENABLE);
10446ab6bfe3SJack F Vogel if (ret_val)
10456ab6bfe3SJack F Vogel goto release;
10466ab6bfe3SJack F Vogel
10476ab6bfe3SJack F Vogel usec_delay(10);
10486ab6bfe3SJack F Vogel
10496ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM6,
10506ab6bfe3SJack F Vogel fextnvm6 | E1000_FEXTNVM6_REQ_PLL_CLK);
10516ab6bfe3SJack F Vogel
10526ab6bfe3SJack F Vogel ret_val =
10536ab6bfe3SJack F Vogel e1000_write_kmrn_reg_locked(hw,
10546ab6bfe3SJack F Vogel E1000_KMRNCTRLSTA_K1_CONFIG,
10557609433eSJack F Vogel reg);
10566ab6bfe3SJack F Vogel release:
10576ab6bfe3SJack F Vogel hw->phy.ops.release(hw);
10586ab6bfe3SJack F Vogel } else {
10596ab6bfe3SJack F Vogel /* clear FEXTNVM6 bit 8 on link down or 10/100 */
10607609433eSJack F Vogel fextnvm6 &= ~E1000_FEXTNVM6_REQ_PLL_CLK;
10617609433eSJack F Vogel
1062c80429ceSEric Joyner if ((hw->phy.revision > 5) || !link ||
1063c80429ceSEric Joyner ((status & E1000_STATUS_SPEED_100) &&
10647609433eSJack F Vogel (status & E1000_STATUS_FD)))
10657609433eSJack F Vogel goto update_fextnvm6;
10667609433eSJack F Vogel
10677609433eSJack F Vogel ret_val = hw->phy.ops.read_reg(hw, I217_INBAND_CTRL, ®);
10687609433eSJack F Vogel if (ret_val)
10697609433eSJack F Vogel return ret_val;
10707609433eSJack F Vogel
10717609433eSJack F Vogel /* Clear link status transmit timeout */
10727609433eSJack F Vogel reg &= ~I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_MASK;
10737609433eSJack F Vogel
10747609433eSJack F Vogel if (status & E1000_STATUS_SPEED_100) {
10757609433eSJack F Vogel /* Set inband Tx timeout to 5x10us for 100Half */
10767609433eSJack F Vogel reg |= 5 << I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT;
10777609433eSJack F Vogel
10787609433eSJack F Vogel /* Do not extend the K1 entry latency for 100Half */
10797609433eSJack F Vogel fextnvm6 &= ~E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION;
10807609433eSJack F Vogel } else {
10817609433eSJack F Vogel /* Set inband Tx timeout to 50x10us for 10Full/Half */
10827609433eSJack F Vogel reg |= 50 <<
10837609433eSJack F Vogel I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT;
10847609433eSJack F Vogel
10857609433eSJack F Vogel /* Extend the K1 entry latency for 10 Mbps */
10867609433eSJack F Vogel fextnvm6 |= E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION;
10877609433eSJack F Vogel }
10887609433eSJack F Vogel
10897609433eSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, I217_INBAND_CTRL, reg);
10907609433eSJack F Vogel if (ret_val)
10917609433eSJack F Vogel return ret_val;
10927609433eSJack F Vogel
10937609433eSJack F Vogel update_fextnvm6:
10947609433eSJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM6, fextnvm6);
10956ab6bfe3SJack F Vogel }
10966ab6bfe3SJack F Vogel
10976ab6bfe3SJack F Vogel return ret_val;
10986ab6bfe3SJack F Vogel }
10996ab6bfe3SJack F Vogel
e1000_ltr2ns(u16 ltr)1100e373323fSSean Bruno static u64 e1000_ltr2ns(u16 ltr)
1101e373323fSSean Bruno {
1102e373323fSSean Bruno u32 value, scale;
1103e373323fSSean Bruno
1104e373323fSSean Bruno /* Determine the latency in nsec based on the LTR value & scale */
1105e373323fSSean Bruno value = ltr & E1000_LTRV_VALUE_MASK;
1106e373323fSSean Bruno scale = (ltr & E1000_LTRV_SCALE_MASK) >> E1000_LTRV_SCALE_SHIFT;
1107e373323fSSean Bruno
110851569bd7SEric Joyner return value * (1ULL << (scale * E1000_LTRV_SCALE_FACTOR));
1109e373323fSSean Bruno }
1110e373323fSSean Bruno
1111e373323fSSean Bruno /**
1112e373323fSSean Bruno * e1000_platform_pm_pch_lpt - Set platform power management values
1113e373323fSSean Bruno * @hw: pointer to the HW structure
1114e373323fSSean Bruno * @link: bool indicating link status
1115e373323fSSean Bruno *
1116e373323fSSean Bruno * Set the Latency Tolerance Reporting (LTR) values for the "PCIe-like"
1117e373323fSSean Bruno * GbE MAC in the Lynx Point PCH based on Rx buffer size and link speed
1118e373323fSSean Bruno * when link is up (which must not exceed the maximum latency supported
1119e373323fSSean Bruno * by the platform), otherwise specify there is no LTR requirement.
11201bbdc25fSKevin Bowling * Unlike true-PCIe devices which set the LTR maximum snoop/no-snoop
1121e373323fSSean Bruno * latencies in the LTR Extended Capability Structure in the PCIe Extended
1122e373323fSSean Bruno * Capability register set, on this device LTR is set by writing the
1123e373323fSSean Bruno * equivalent snoop/no-snoop latencies in the LTRV register in the MAC and
1124e373323fSSean Bruno * set the SEND bit to send an Intel On-chip System Fabric sideband (IOSF-SB)
1125e373323fSSean Bruno * message to the PMC.
1126e373323fSSean Bruno *
1127e373323fSSean Bruno * Use the LTR value to calculate the Optimized Buffer Flush/Fill (OBFF)
1128e373323fSSean Bruno * high-water mark.
1129e373323fSSean Bruno **/
e1000_platform_pm_pch_lpt(struct e1000_hw * hw,bool link)1130e373323fSSean Bruno static s32 e1000_platform_pm_pch_lpt(struct e1000_hw *hw, bool link)
1131e373323fSSean Bruno {
1132e373323fSSean Bruno u32 reg = link << (E1000_LTRV_REQ_SHIFT + E1000_LTRV_NOSNOOP_SHIFT) |
1133e373323fSSean Bruno link << E1000_LTRV_REQ_SHIFT | E1000_LTRV_SEND;
1134e373323fSSean Bruno u16 lat_enc = 0; /* latency encoded */
1135e373323fSSean Bruno s32 obff_hwm = 0;
1136e373323fSSean Bruno
1137e373323fSSean Bruno DEBUGFUNC("e1000_platform_pm_pch_lpt");
1138e373323fSSean Bruno
1139e373323fSSean Bruno if (link) {
1140e373323fSSean Bruno u16 speed, duplex, scale = 0;
1141e373323fSSean Bruno u16 max_snoop, max_nosnoop;
1142e373323fSSean Bruno u16 max_ltr_enc; /* max LTR latency encoded */
1143e373323fSSean Bruno s64 lat_ns;
1144e373323fSSean Bruno s64 value;
1145e373323fSSean Bruno u32 rxa;
1146e373323fSSean Bruno
1147e373323fSSean Bruno if (!hw->mac.max_frame_size) {
1148e373323fSSean Bruno DEBUGOUT("max_frame_size not set.\n");
1149e373323fSSean Bruno return -E1000_ERR_CONFIG;
1150e373323fSSean Bruno }
1151e373323fSSean Bruno
1152e373323fSSean Bruno hw->mac.ops.get_link_up_info(hw, &speed, &duplex);
1153e373323fSSean Bruno if (!speed) {
1154e373323fSSean Bruno DEBUGOUT("Speed not set.\n");
1155e373323fSSean Bruno return -E1000_ERR_CONFIG;
1156e373323fSSean Bruno }
1157e373323fSSean Bruno
1158e373323fSSean Bruno /* Rx Packet Buffer Allocation size (KB) */
1159e373323fSSean Bruno rxa = E1000_READ_REG(hw, E1000_PBA) & E1000_PBA_RXA_MASK;
1160e373323fSSean Bruno
1161e373323fSSean Bruno /* Determine the maximum latency tolerated by the device.
1162e373323fSSean Bruno *
1163e373323fSSean Bruno * Per the PCIe spec, the tolerated latencies are encoded as
1164e373323fSSean Bruno * a 3-bit encoded scale (only 0-5 are valid) multiplied by
1165e373323fSSean Bruno * a 10-bit value (0-1023) to provide a range from 1 ns to
1166e373323fSSean Bruno * 2^25*(2^10-1) ns. The scale is encoded as 0=2^0ns,
1167e373323fSSean Bruno * 1=2^5ns, 2=2^10ns,...5=2^25ns.
1168e373323fSSean Bruno */
1169e373323fSSean Bruno lat_ns = ((s64)rxa * 1024 -
1170e373323fSSean Bruno (2 * (s64)hw->mac.max_frame_size)) * 8 * 1000;
1171e373323fSSean Bruno if (lat_ns < 0)
1172e373323fSSean Bruno lat_ns = 0;
1173e373323fSSean Bruno else
1174e373323fSSean Bruno lat_ns /= speed;
1175e373323fSSean Bruno value = lat_ns;
1176e373323fSSean Bruno
1177e373323fSSean Bruno while (value > E1000_LTRV_VALUE_MASK) {
1178e373323fSSean Bruno scale++;
1179e373323fSSean Bruno value = E1000_DIVIDE_ROUND_UP(value, (1 << 5));
1180e373323fSSean Bruno }
1181e373323fSSean Bruno if (scale > E1000_LTRV_SCALE_MAX) {
1182e373323fSSean Bruno DEBUGOUT1("Invalid LTR latency scale %d\n", scale);
1183e373323fSSean Bruno return -E1000_ERR_CONFIG;
1184e373323fSSean Bruno }
1185e373323fSSean Bruno lat_enc = (u16)((scale << E1000_LTRV_SCALE_SHIFT) | value);
1186e373323fSSean Bruno
1187e373323fSSean Bruno /* Determine the maximum latency tolerated by the platform */
1188e373323fSSean Bruno e1000_read_pci_cfg(hw, E1000_PCI_LTR_CAP_LPT, &max_snoop);
1189e373323fSSean Bruno e1000_read_pci_cfg(hw, E1000_PCI_LTR_CAP_LPT + 2, &max_nosnoop);
1190e373323fSSean Bruno max_ltr_enc = E1000_MAX(max_snoop, max_nosnoop);
1191e373323fSSean Bruno
1192e373323fSSean Bruno if (lat_enc > max_ltr_enc) {
1193e373323fSSean Bruno lat_enc = max_ltr_enc;
1194e373323fSSean Bruno lat_ns = e1000_ltr2ns(max_ltr_enc);
1195e373323fSSean Bruno }
1196e373323fSSean Bruno
1197e373323fSSean Bruno if (lat_ns) {
1198e373323fSSean Bruno lat_ns *= speed * 1000;
1199e373323fSSean Bruno lat_ns /= 8;
1200e373323fSSean Bruno lat_ns /= 1000000000;
1201e373323fSSean Bruno obff_hwm = (s32)(rxa - lat_ns);
1202e373323fSSean Bruno }
1203e373323fSSean Bruno if ((obff_hwm < 0) || (obff_hwm > E1000_SVT_OFF_HWM_MASK)) {
1204e373323fSSean Bruno DEBUGOUT1("Invalid high water mark %d\n", obff_hwm);
1205e373323fSSean Bruno return -E1000_ERR_CONFIG;
1206e373323fSSean Bruno }
1207e373323fSSean Bruno }
1208e373323fSSean Bruno
1209e373323fSSean Bruno /* Set Snoop and No-Snoop latencies the same */
1210e373323fSSean Bruno reg |= lat_enc | (lat_enc << E1000_LTRV_NOSNOOP_SHIFT);
1211e373323fSSean Bruno E1000_WRITE_REG(hw, E1000_LTRV, reg);
1212e373323fSSean Bruno
1213e373323fSSean Bruno /* Set OBFF high water mark */
1214e373323fSSean Bruno reg = E1000_READ_REG(hw, E1000_SVT) & ~E1000_SVT_OFF_HWM_MASK;
1215e373323fSSean Bruno reg |= obff_hwm;
1216e373323fSSean Bruno E1000_WRITE_REG(hw, E1000_SVT, reg);
1217e373323fSSean Bruno
1218e373323fSSean Bruno /* Enable OBFF */
1219e373323fSSean Bruno reg = E1000_READ_REG(hw, E1000_SVCR);
1220e373323fSSean Bruno reg |= E1000_SVCR_OFF_EN;
1221e373323fSSean Bruno /* Always unblock interrupts to the CPU even when the system is
1222e373323fSSean Bruno * in OBFF mode. This ensures that small round-robin traffic
1223e373323fSSean Bruno * (like ping) does not get dropped or experience long latency.
1224e373323fSSean Bruno */
1225e373323fSSean Bruno reg |= E1000_SVCR_OFF_MASKINT;
1226e373323fSSean Bruno E1000_WRITE_REG(hw, E1000_SVCR, reg);
1227e373323fSSean Bruno
1228e373323fSSean Bruno return E1000_SUCCESS;
1229e373323fSSean Bruno }
1230e373323fSSean Bruno
1231e373323fSSean Bruno /**
1232e373323fSSean Bruno * e1000_set_obff_timer_pch_lpt - Update Optimized Buffer Flush/Fill timer
1233e373323fSSean Bruno * @hw: pointer to the HW structure
1234e373323fSSean Bruno * @itr: interrupt throttling rate
1235e373323fSSean Bruno *
1236e373323fSSean Bruno * Configure OBFF with the updated interrupt rate.
1237e373323fSSean Bruno **/
e1000_set_obff_timer_pch_lpt(struct e1000_hw * hw,u32 itr)1238e373323fSSean Bruno static s32 e1000_set_obff_timer_pch_lpt(struct e1000_hw *hw, u32 itr)
1239e373323fSSean Bruno {
1240e373323fSSean Bruno u32 svcr;
1241e373323fSSean Bruno s32 timer;
1242e373323fSSean Bruno
1243e373323fSSean Bruno DEBUGFUNC("e1000_set_obff_timer_pch_lpt");
1244e373323fSSean Bruno
1245e373323fSSean Bruno /* Convert ITR value into microseconds for OBFF timer */
1246e373323fSSean Bruno timer = itr & E1000_ITR_MASK;
1247e373323fSSean Bruno timer = (timer * E1000_ITR_MULT) / 1000;
1248e373323fSSean Bruno
1249e373323fSSean Bruno if ((timer < 0) || (timer > E1000_ITR_MASK)) {
1250e373323fSSean Bruno DEBUGOUT1("Invalid OBFF timer %d\n", timer);
1251e373323fSSean Bruno return -E1000_ERR_CONFIG;
1252e373323fSSean Bruno }
1253e373323fSSean Bruno
1254e373323fSSean Bruno svcr = E1000_READ_REG(hw, E1000_SVCR);
1255e373323fSSean Bruno svcr &= ~E1000_SVCR_OFF_TIMER_MASK;
1256e373323fSSean Bruno svcr |= timer << E1000_SVCR_OFF_TIMER_SHIFT;
1257e373323fSSean Bruno E1000_WRITE_REG(hw, E1000_SVCR, svcr);
1258e373323fSSean Bruno
1259e373323fSSean Bruno return E1000_SUCCESS;
1260e373323fSSean Bruno }
1261e373323fSSean Bruno
12627d9119bdSJack F Vogel /**
12638cc64f1eSJack F Vogel * e1000_enable_ulp_lpt_lp - configure Ultra Low Power mode for LynxPoint-LP
12648cc64f1eSJack F Vogel * @hw: pointer to the HW structure
12658cc64f1eSJack F Vogel * @to_sx: boolean indicating a system power state transition to Sx
12668cc64f1eSJack F Vogel *
12678cc64f1eSJack F Vogel * When link is down, configure ULP mode to significantly reduce the power
12688cc64f1eSJack F Vogel * to the PHY. If on a Manageability Engine (ME) enabled system, tell the
12698cc64f1eSJack F Vogel * ME firmware to start the ULP configuration. If not on an ME enabled
12708cc64f1eSJack F Vogel * system, configure the ULP mode by software.
12718cc64f1eSJack F Vogel */
e1000_enable_ulp_lpt_lp(struct e1000_hw * hw,bool to_sx)12728cc64f1eSJack F Vogel s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx)
12738cc64f1eSJack F Vogel {
12748cc64f1eSJack F Vogel u32 mac_reg;
12758cc64f1eSJack F Vogel s32 ret_val = E1000_SUCCESS;
12768cc64f1eSJack F Vogel u16 phy_reg;
1277c80429ceSEric Joyner u16 oem_reg = 0;
12788cc64f1eSJack F Vogel
12798cc64f1eSJack F Vogel if ((hw->mac.type < e1000_pch_lpt) ||
12808cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_LM) ||
12818cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_V) ||
12828cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_I218_LM2) ||
12838cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_I218_V2) ||
12848cc64f1eSJack F Vogel (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_on))
12858cc64f1eSJack F Vogel return 0;
12868cc64f1eSJack F Vogel
1287fc7682b1SKevin Bowling if (E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID) {
1288fc7682b1SKevin Bowling /* Request ME configure ULP mode in the PHY */
1289fc7682b1SKevin Bowling mac_reg = E1000_READ_REG(hw, E1000_H2ME);
1290fc7682b1SKevin Bowling mac_reg |= E1000_H2ME_ULP | E1000_H2ME_ENFORCE_SETTINGS;
1291fc7682b1SKevin Bowling E1000_WRITE_REG(hw, E1000_H2ME, mac_reg);
1292fc7682b1SKevin Bowling
1293fc7682b1SKevin Bowling goto out;
12948cc64f1eSJack F Vogel }
12958cc64f1eSJack F Vogel
1296a4378873SKevin Bowling if (!to_sx) {
1297a4378873SKevin Bowling int i = 0;
1298a4378873SKevin Bowling /* Poll up to 5 seconds for Cable Disconnected indication */
1299a4378873SKevin Bowling while (!(E1000_READ_REG(hw, E1000_FEXT) &
1300a4378873SKevin Bowling E1000_FEXT_PHY_CABLE_DISCONNECTED)) {
1301a4378873SKevin Bowling /* Bail if link is re-acquired */
1302a4378873SKevin Bowling if (E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)
1303a4378873SKevin Bowling return -E1000_ERR_PHY;
1304a4378873SKevin Bowling if (i++ == 100)
1305a4378873SKevin Bowling break;
1306a4378873SKevin Bowling
1307a4378873SKevin Bowling msec_delay(50);
1308a4378873SKevin Bowling }
1309a4378873SKevin Bowling DEBUGOUT2("CABLE_DISCONNECTED %s set after %dmsec\n",
1310a4378873SKevin Bowling (E1000_READ_REG(hw, E1000_FEXT) &
1311a4378873SKevin Bowling E1000_FEXT_PHY_CABLE_DISCONNECTED) ? "" : "not",
1312a4378873SKevin Bowling i * 50);
131340fa6e53SWenzhuo Lu if (!(E1000_READ_REG(hw, E1000_FEXT) &
131440fa6e53SWenzhuo Lu E1000_FEXT_PHY_CABLE_DISCONNECTED))
131540fa6e53SWenzhuo Lu return 0;
1316a4378873SKevin Bowling }
1317a4378873SKevin Bowling
13188cc64f1eSJack F Vogel ret_val = hw->phy.ops.acquire(hw);
13198cc64f1eSJack F Vogel if (ret_val)
13208cc64f1eSJack F Vogel goto out;
13218cc64f1eSJack F Vogel
13228cc64f1eSJack F Vogel /* Force SMBus mode in PHY */
13238cc64f1eSJack F Vogel ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg);
13248cc64f1eSJack F Vogel if (ret_val)
13258cc64f1eSJack F Vogel goto release;
13268cc64f1eSJack F Vogel phy_reg |= CV_SMB_CTRL_FORCE_SMBUS;
13278cc64f1eSJack F Vogel e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg);
13288cc64f1eSJack F Vogel
13298cc64f1eSJack F Vogel /* Force SMBus mode in MAC */
13308cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
13318cc64f1eSJack F Vogel mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
13328cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
13338cc64f1eSJack F Vogel
1334a4378873SKevin Bowling /* Si workaround for ULP entry flow on i127/rev6 h/w. Enable
1335c80429ceSEric Joyner * LPLU and disable Gig speed when entering ULP
1336c80429ceSEric Joyner */
1337c80429ceSEric Joyner if ((hw->phy.type == e1000_phy_i217) && (hw->phy.revision == 6)) {
1338c80429ceSEric Joyner ret_val = e1000_read_phy_reg_hv_locked(hw, HV_OEM_BITS,
1339c80429ceSEric Joyner &oem_reg);
1340c80429ceSEric Joyner if (ret_val)
1341c80429ceSEric Joyner goto release;
1342c80429ceSEric Joyner
1343c80429ceSEric Joyner phy_reg = oem_reg;
1344c80429ceSEric Joyner phy_reg |= HV_OEM_BITS_LPLU | HV_OEM_BITS_GBE_DIS;
1345c80429ceSEric Joyner
1346c80429ceSEric Joyner ret_val = e1000_write_phy_reg_hv_locked(hw, HV_OEM_BITS,
1347c80429ceSEric Joyner phy_reg);
1348c80429ceSEric Joyner
1349c80429ceSEric Joyner if (ret_val)
1350c80429ceSEric Joyner goto release;
1351c80429ceSEric Joyner }
1352c80429ceSEric Joyner
13538cc64f1eSJack F Vogel /* Set Inband ULP Exit, Reset to SMBus mode and
13548cc64f1eSJack F Vogel * Disable SMBus Release on PERST# in PHY
13558cc64f1eSJack F Vogel */
13568cc64f1eSJack F Vogel ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg);
13578cc64f1eSJack F Vogel if (ret_val)
13588cc64f1eSJack F Vogel goto release;
13598cc64f1eSJack F Vogel phy_reg |= (I218_ULP_CONFIG1_RESET_TO_SMBUS |
13608cc64f1eSJack F Vogel I218_ULP_CONFIG1_DISABLE_SMB_PERST);
13618cc64f1eSJack F Vogel if (to_sx) {
13628cc64f1eSJack F Vogel if (E1000_READ_REG(hw, E1000_WUFC) & E1000_WUFC_LNKC)
13638cc64f1eSJack F Vogel phy_reg |= I218_ULP_CONFIG1_WOL_HOST;
1364c80429ceSEric Joyner else
1365c80429ceSEric Joyner phy_reg &= ~I218_ULP_CONFIG1_WOL_HOST;
13668cc64f1eSJack F Vogel
13678cc64f1eSJack F Vogel phy_reg |= I218_ULP_CONFIG1_STICKY_ULP;
1368c80429ceSEric Joyner phy_reg &= ~I218_ULP_CONFIG1_INBAND_EXIT;
13698cc64f1eSJack F Vogel } else {
13708cc64f1eSJack F Vogel phy_reg |= I218_ULP_CONFIG1_INBAND_EXIT;
1371c80429ceSEric Joyner phy_reg &= ~I218_ULP_CONFIG1_STICKY_ULP;
1372c80429ceSEric Joyner phy_reg &= ~I218_ULP_CONFIG1_WOL_HOST;
13738cc64f1eSJack F Vogel }
13748cc64f1eSJack F Vogel e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
13758cc64f1eSJack F Vogel
13768cc64f1eSJack F Vogel /* Set Disable SMBus Release on PERST# in MAC */
13778cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM7);
13788cc64f1eSJack F Vogel mac_reg |= E1000_FEXTNVM7_DISABLE_SMB_PERST;
13798cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM7, mac_reg);
13808cc64f1eSJack F Vogel
13818cc64f1eSJack F Vogel /* Commit ULP changes in PHY by starting auto ULP configuration */
13828cc64f1eSJack F Vogel phy_reg |= I218_ULP_CONFIG1_START;
13838cc64f1eSJack F Vogel e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
1384c80429ceSEric Joyner
1385c80429ceSEric Joyner if ((hw->phy.type == e1000_phy_i217) && (hw->phy.revision == 6) &&
1386c80429ceSEric Joyner to_sx && (E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
1387c80429ceSEric Joyner ret_val = e1000_write_phy_reg_hv_locked(hw, HV_OEM_BITS,
1388c80429ceSEric Joyner oem_reg);
1389c80429ceSEric Joyner if (ret_val)
1390c80429ceSEric Joyner goto release;
1391c80429ceSEric Joyner }
1392c80429ceSEric Joyner
13938cc64f1eSJack F Vogel release:
13948cc64f1eSJack F Vogel hw->phy.ops.release(hw);
13958cc64f1eSJack F Vogel out:
13968cc64f1eSJack F Vogel if (ret_val)
13978cc64f1eSJack F Vogel DEBUGOUT1("Error in ULP enable flow: %d\n", ret_val);
13988cc64f1eSJack F Vogel else
13998cc64f1eSJack F Vogel hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_on;
14008cc64f1eSJack F Vogel
14018cc64f1eSJack F Vogel return ret_val;
14028cc64f1eSJack F Vogel }
14038cc64f1eSJack F Vogel
14048cc64f1eSJack F Vogel /**
14058cc64f1eSJack F Vogel * e1000_disable_ulp_lpt_lp - unconfigure Ultra Low Power mode for LynxPoint-LP
14068cc64f1eSJack F Vogel * @hw: pointer to the HW structure
14078cc64f1eSJack F Vogel * @force: boolean indicating whether or not to force disabling ULP
14088cc64f1eSJack F Vogel *
14098cc64f1eSJack F Vogel * Un-configure ULP mode when link is up, the system is transitioned from
14108cc64f1eSJack F Vogel * Sx or the driver is unloaded. If on a Manageability Engine (ME) enabled
14118cc64f1eSJack F Vogel * system, poll for an indication from ME that ULP has been un-configured.
14128cc64f1eSJack F Vogel * If not on an ME enabled system, un-configure the ULP mode by software.
14138cc64f1eSJack F Vogel *
14148cc64f1eSJack F Vogel * During nominal operation, this function is called when link is acquired
14151bbdc25fSKevin Bowling * to disable ULP mode (force=false); otherwise, for example when unloading
14161bbdc25fSKevin Bowling * the driver or during Sx->S0 transitions, this is called with force=true
14178cc64f1eSJack F Vogel * to forcibly disable ULP.
14188cc64f1eSJack F Vogel */
e1000_disable_ulp_lpt_lp(struct e1000_hw * hw,bool force)14198cc64f1eSJack F Vogel s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force)
14208cc64f1eSJack F Vogel {
14218cc64f1eSJack F Vogel s32 ret_val = E1000_SUCCESS;
1422e8e3171dSGuinan Sun u8 ulp_exit_timeout = 30;
14238cc64f1eSJack F Vogel u32 mac_reg;
14248cc64f1eSJack F Vogel u16 phy_reg;
14258cc64f1eSJack F Vogel int i = 0;
14268cc64f1eSJack F Vogel
14278cc64f1eSJack F Vogel if ((hw->mac.type < e1000_pch_lpt) ||
14288cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_LM) ||
14298cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_V) ||
14308cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_I218_LM2) ||
14318cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_I218_V2) ||
14328cc64f1eSJack F Vogel (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_off))
14338cc64f1eSJack F Vogel return 0;
14348cc64f1eSJack F Vogel
14358cc64f1eSJack F Vogel if (E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID) {
14368cc64f1eSJack F Vogel if (force) {
14378cc64f1eSJack F Vogel /* Request ME un-configure ULP mode in the PHY */
14388cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_H2ME);
14398cc64f1eSJack F Vogel mac_reg &= ~E1000_H2ME_ULP;
14408cc64f1eSJack F Vogel mac_reg |= E1000_H2ME_ENFORCE_SETTINGS;
14418cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_H2ME, mac_reg);
14428cc64f1eSJack F Vogel }
14438cc64f1eSJack F Vogel
1444e8e3171dSGuinan Sun if (hw->mac.type == e1000_pch_cnp)
1445e8e3171dSGuinan Sun ulp_exit_timeout = 100;
1446e8e3171dSGuinan Sun
14478cc64f1eSJack F Vogel while (E1000_READ_REG(hw, E1000_FWSM) &
14488cc64f1eSJack F Vogel E1000_FWSM_ULP_CFG_DONE) {
1449e8e3171dSGuinan Sun if (i++ == ulp_exit_timeout) {
14508cc64f1eSJack F Vogel ret_val = -E1000_ERR_PHY;
14518cc64f1eSJack F Vogel goto out;
14528cc64f1eSJack F Vogel }
14538cc64f1eSJack F Vogel
14548cc64f1eSJack F Vogel msec_delay(10);
14558cc64f1eSJack F Vogel }
14568cc64f1eSJack F Vogel DEBUGOUT1("ULP_CONFIG_DONE cleared after %dmsec\n", i * 10);
14578cc64f1eSJack F Vogel
14588cc64f1eSJack F Vogel if (force) {
14598cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_H2ME);
14608cc64f1eSJack F Vogel mac_reg &= ~E1000_H2ME_ENFORCE_SETTINGS;
14618cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_H2ME, mac_reg);
14628cc64f1eSJack F Vogel } else {
14638cc64f1eSJack F Vogel /* Clear H2ME.ULP after ME ULP configuration */
14648cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_H2ME);
14658cc64f1eSJack F Vogel mac_reg &= ~E1000_H2ME_ULP;
14668cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_H2ME, mac_reg);
14678cc64f1eSJack F Vogel }
14688cc64f1eSJack F Vogel
14698cc64f1eSJack F Vogel goto out;
14708cc64f1eSJack F Vogel }
14718cc64f1eSJack F Vogel
14728cc64f1eSJack F Vogel ret_val = hw->phy.ops.acquire(hw);
14738cc64f1eSJack F Vogel if (ret_val)
14748cc64f1eSJack F Vogel goto out;
14758cc64f1eSJack F Vogel
14768cc64f1eSJack F Vogel if (force)
14778cc64f1eSJack F Vogel /* Toggle LANPHYPC Value bit */
14788cc64f1eSJack F Vogel e1000_toggle_lanphypc_pch_lpt(hw);
14798cc64f1eSJack F Vogel
14808cc64f1eSJack F Vogel /* Unforce SMBus mode in PHY */
14818cc64f1eSJack F Vogel ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg);
14828cc64f1eSJack F Vogel if (ret_val) {
14838cc64f1eSJack F Vogel /* The MAC might be in PCIe mode, so temporarily force to
14848cc64f1eSJack F Vogel * SMBus mode in order to access the PHY.
14858cc64f1eSJack F Vogel */
14868cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
14878cc64f1eSJack F Vogel mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
14888cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
14898cc64f1eSJack F Vogel
14908cc64f1eSJack F Vogel msec_delay(50);
14918cc64f1eSJack F Vogel
14928cc64f1eSJack F Vogel ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL,
14938cc64f1eSJack F Vogel &phy_reg);
14948cc64f1eSJack F Vogel if (ret_val)
14958cc64f1eSJack F Vogel goto release;
14968cc64f1eSJack F Vogel }
14978cc64f1eSJack F Vogel phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
14988cc64f1eSJack F Vogel e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg);
14998cc64f1eSJack F Vogel
15008cc64f1eSJack F Vogel /* Unforce SMBus mode in MAC */
15018cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
15028cc64f1eSJack F Vogel mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
15038cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
15048cc64f1eSJack F Vogel
15058cc64f1eSJack F Vogel /* When ULP mode was previously entered, K1 was disabled by the
15068cc64f1eSJack F Vogel * hardware. Re-Enable K1 in the PHY when exiting ULP.
15078cc64f1eSJack F Vogel */
15088cc64f1eSJack F Vogel ret_val = e1000_read_phy_reg_hv_locked(hw, HV_PM_CTRL, &phy_reg);
15098cc64f1eSJack F Vogel if (ret_val)
15108cc64f1eSJack F Vogel goto release;
15118cc64f1eSJack F Vogel phy_reg |= HV_PM_CTRL_K1_ENABLE;
15128cc64f1eSJack F Vogel e1000_write_phy_reg_hv_locked(hw, HV_PM_CTRL, phy_reg);
15138cc64f1eSJack F Vogel
15148cc64f1eSJack F Vogel /* Clear ULP enabled configuration */
15158cc64f1eSJack F Vogel ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg);
15168cc64f1eSJack F Vogel if (ret_val)
15178cc64f1eSJack F Vogel goto release;
15188cc64f1eSJack F Vogel phy_reg &= ~(I218_ULP_CONFIG1_IND |
15198cc64f1eSJack F Vogel I218_ULP_CONFIG1_STICKY_ULP |
15208cc64f1eSJack F Vogel I218_ULP_CONFIG1_RESET_TO_SMBUS |
15218cc64f1eSJack F Vogel I218_ULP_CONFIG1_WOL_HOST |
15228cc64f1eSJack F Vogel I218_ULP_CONFIG1_INBAND_EXIT |
1523c80429ceSEric Joyner I218_ULP_CONFIG1_EN_ULP_LANPHYPC |
1524c80429ceSEric Joyner I218_ULP_CONFIG1_DIS_CLR_STICKY_ON_PERST |
15258cc64f1eSJack F Vogel I218_ULP_CONFIG1_DISABLE_SMB_PERST);
15268cc64f1eSJack F Vogel e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
15278cc64f1eSJack F Vogel
15288cc64f1eSJack F Vogel /* Commit ULP changes by starting auto ULP configuration */
15298cc64f1eSJack F Vogel phy_reg |= I218_ULP_CONFIG1_START;
15308cc64f1eSJack F Vogel e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
15318cc64f1eSJack F Vogel
15328cc64f1eSJack F Vogel /* Clear Disable SMBus Release on PERST# in MAC */
15338cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM7);
15348cc64f1eSJack F Vogel mac_reg &= ~E1000_FEXTNVM7_DISABLE_SMB_PERST;
15358cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM7, mac_reg);
15368cc64f1eSJack F Vogel
15378cc64f1eSJack F Vogel release:
15388cc64f1eSJack F Vogel hw->phy.ops.release(hw);
15398cc64f1eSJack F Vogel if (force) {
15408cc64f1eSJack F Vogel hw->phy.ops.reset(hw);
15418cc64f1eSJack F Vogel msec_delay(50);
15428cc64f1eSJack F Vogel }
15438cc64f1eSJack F Vogel out:
15448cc64f1eSJack F Vogel if (ret_val)
15458cc64f1eSJack F Vogel DEBUGOUT1("Error in ULP disable flow: %d\n", ret_val);
15468cc64f1eSJack F Vogel else
15478cc64f1eSJack F Vogel hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_off;
15488cc64f1eSJack F Vogel
15498cc64f1eSJack F Vogel return ret_val;
15508cc64f1eSJack F Vogel }
15518cc64f1eSJack F Vogel
15528cc64f1eSJack F Vogel /**
15534edd8523SJack F Vogel * e1000_check_for_copper_link_ich8lan - Check for link (Copper)
15544edd8523SJack F Vogel * @hw: pointer to the HW structure
15554edd8523SJack F Vogel *
15564edd8523SJack F Vogel * Checks to see of the link status of the hardware has changed. If a
15574edd8523SJack F Vogel * change in link status has been detected, then we read the PHY registers
15584edd8523SJack F Vogel * to get the current speed/duplex if link exists.
15594edd8523SJack F Vogel **/
e1000_check_for_copper_link_ich8lan(struct e1000_hw * hw)15604edd8523SJack F Vogel static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
15614edd8523SJack F Vogel {
15624edd8523SJack F Vogel struct e1000_mac_info *mac = &hw->mac;
1563c80429ceSEric Joyner s32 ret_val, tipg_reg = 0;
1564c80429ceSEric Joyner u16 emi_addr, emi_val = 0;
1565a4378873SKevin Bowling bool link;
15664dab5c37SJack F Vogel u16 phy_reg;
15674edd8523SJack F Vogel
15684edd8523SJack F Vogel DEBUGFUNC("e1000_check_for_copper_link_ich8lan");
15694edd8523SJack F Vogel
15706ab6bfe3SJack F Vogel /* We only want to go out to the PHY registers to see if Auto-Neg
15714edd8523SJack F Vogel * has completed and/or if our link status has changed. The
15724edd8523SJack F Vogel * get_link_status flag is set upon receiving a Link Status
15734edd8523SJack F Vogel * Change or Rx Sequence Error interrupt.
15744edd8523SJack F Vogel */
15756ab6bfe3SJack F Vogel if (!mac->get_link_status)
15766ab6bfe3SJack F Vogel return E1000_SUCCESS;
15774edd8523SJack F Vogel
15786ab6bfe3SJack F Vogel /* First we want to see if the MII Status Register reports
15794edd8523SJack F Vogel * link. If so, then we want to get the current speed/duplex
15804edd8523SJack F Vogel * of the PHY.
15814edd8523SJack F Vogel */
15824edd8523SJack F Vogel ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
15834edd8523SJack F Vogel if (ret_val)
15846ab6bfe3SJack F Vogel return ret_val;
15854edd8523SJack F Vogel
15864edd8523SJack F Vogel if (hw->mac.type == e1000_pchlan) {
15874edd8523SJack F Vogel ret_val = e1000_k1_gig_workaround_hv(hw, link);
15884edd8523SJack F Vogel if (ret_val)
15896ab6bfe3SJack F Vogel return ret_val;
15904edd8523SJack F Vogel }
15914edd8523SJack F Vogel
15928cc64f1eSJack F Vogel /* When connected at 10Mbps half-duplex, some parts are excessively
15936ab6bfe3SJack F Vogel * aggressive resulting in many collisions. To avoid this, increase
15946ab6bfe3SJack F Vogel * the IPG and reduce Rx latency in the PHY.
15956ab6bfe3SJack F Vogel */
1596295df609SEric Joyner if ((hw->mac.type >= e1000_pch2lan) && link) {
1597c80429ceSEric Joyner u16 speed, duplex;
15988cc64f1eSJack F Vogel
1599c80429ceSEric Joyner e1000_get_speed_and_duplex_copper_generic(hw, &speed, &duplex);
1600c80429ceSEric Joyner tipg_reg = E1000_READ_REG(hw, E1000_TIPG);
1601c80429ceSEric Joyner tipg_reg &= ~E1000_TIPG_IPGT_MASK;
16026ab6bfe3SJack F Vogel
1603c80429ceSEric Joyner if (duplex == HALF_DUPLEX && speed == SPEED_10) {
1604c80429ceSEric Joyner tipg_reg |= 0xFF;
16056ab6bfe3SJack F Vogel /* Reduce Rx latency in analog PHY */
1606c80429ceSEric Joyner emi_val = 0;
1607295df609SEric Joyner } else if (hw->mac.type >= e1000_pch_spt &&
1608c80429ceSEric Joyner duplex == FULL_DUPLEX && speed != SPEED_1000) {
1609c80429ceSEric Joyner tipg_reg |= 0xC;
1610c80429ceSEric Joyner emi_val = 1;
1611c80429ceSEric Joyner } else {
1612c80429ceSEric Joyner /* Roll back the default values */
1613c80429ceSEric Joyner tipg_reg |= 0x08;
1614c80429ceSEric Joyner emi_val = 1;
1615c80429ceSEric Joyner }
1616c80429ceSEric Joyner
1617c80429ceSEric Joyner E1000_WRITE_REG(hw, E1000_TIPG, tipg_reg);
1618c80429ceSEric Joyner
16196ab6bfe3SJack F Vogel ret_val = hw->phy.ops.acquire(hw);
16206ab6bfe3SJack F Vogel if (ret_val)
16216ab6bfe3SJack F Vogel return ret_val;
16226ab6bfe3SJack F Vogel
16238cc64f1eSJack F Vogel if (hw->mac.type == e1000_pch2lan)
16248cc64f1eSJack F Vogel emi_addr = I82579_RX_CONFIG;
16258cc64f1eSJack F Vogel else
16268cc64f1eSJack F Vogel emi_addr = I217_RX_CONFIG;
1627c80429ceSEric Joyner ret_val = e1000_write_emi_reg_locked(hw, emi_addr, emi_val);
16286ab6bfe3SJack F Vogel
1629295df609SEric Joyner
1630295df609SEric Joyner if (hw->mac.type >= e1000_pch_lpt) {
1631c80429ceSEric Joyner hw->phy.ops.read_reg_locked(hw, I217_PLL_CLOCK_GATE_REG,
1632c80429ceSEric Joyner &phy_reg);
1633c80429ceSEric Joyner phy_reg &= ~I217_PLL_CLOCK_GATE_MASK;
1634c80429ceSEric Joyner if (speed == SPEED_100 || speed == SPEED_10)
1635c80429ceSEric Joyner phy_reg |= 0x3E8;
1636c80429ceSEric Joyner else
1637c80429ceSEric Joyner phy_reg |= 0xFA;
1638c80429ceSEric Joyner hw->phy.ops.write_reg_locked(hw,
1639c80429ceSEric Joyner I217_PLL_CLOCK_GATE_REG,
1640c80429ceSEric Joyner phy_reg);
1641e760e292SSean Bruno
1642e760e292SSean Bruno if (speed == SPEED_1000) {
1643e760e292SSean Bruno hw->phy.ops.read_reg_locked(hw, HV_PM_CTRL,
1644e760e292SSean Bruno &phy_reg);
1645e760e292SSean Bruno
1646e760e292SSean Bruno phy_reg |= HV_PM_CTRL_K1_CLK_REQ;
1647e760e292SSean Bruno
1648e760e292SSean Bruno hw->phy.ops.write_reg_locked(hw, HV_PM_CTRL,
1649e760e292SSean Bruno phy_reg);
1650e760e292SSean Bruno }
1651c80429ceSEric Joyner }
16526ab6bfe3SJack F Vogel hw->phy.ops.release(hw);
16536ab6bfe3SJack F Vogel
16546ab6bfe3SJack F Vogel if (ret_val)
16556ab6bfe3SJack F Vogel return ret_val;
1656c80429ceSEric Joyner
1657295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt) {
1658c80429ceSEric Joyner u16 data;
1659c80429ceSEric Joyner u16 ptr_gap;
1660c80429ceSEric Joyner
1661c80429ceSEric Joyner if (speed == SPEED_1000) {
1662c80429ceSEric Joyner ret_val = hw->phy.ops.acquire(hw);
1663c80429ceSEric Joyner if (ret_val)
1664c80429ceSEric Joyner return ret_val;
1665c80429ceSEric Joyner
1666c80429ceSEric Joyner ret_val = hw->phy.ops.read_reg_locked(hw,
1667c80429ceSEric Joyner PHY_REG(776, 20),
1668c80429ceSEric Joyner &data);
1669c80429ceSEric Joyner if (ret_val) {
1670c80429ceSEric Joyner hw->phy.ops.release(hw);
1671c80429ceSEric Joyner return ret_val;
16726ab6bfe3SJack F Vogel }
1673c80429ceSEric Joyner
1674c80429ceSEric Joyner ptr_gap = (data & (0x3FF << 2)) >> 2;
1675c80429ceSEric Joyner if (ptr_gap < 0x18) {
1676c80429ceSEric Joyner data &= ~(0x3FF << 2);
1677c80429ceSEric Joyner data |= (0x18 << 2);
1678c80429ceSEric Joyner ret_val =
1679c80429ceSEric Joyner hw->phy.ops.write_reg_locked(hw,
1680c80429ceSEric Joyner PHY_REG(776, 20), data);
1681c80429ceSEric Joyner }
1682c80429ceSEric Joyner hw->phy.ops.release(hw);
1683c80429ceSEric Joyner if (ret_val)
1684c80429ceSEric Joyner return ret_val;
1685c80429ceSEric Joyner } else {
1686c80429ceSEric Joyner ret_val = hw->phy.ops.acquire(hw);
1687c80429ceSEric Joyner if (ret_val)
1688c80429ceSEric Joyner return ret_val;
1689c80429ceSEric Joyner
1690c80429ceSEric Joyner ret_val = hw->phy.ops.write_reg_locked(hw,
1691c80429ceSEric Joyner PHY_REG(776, 20),
1692c80429ceSEric Joyner 0xC023);
1693c80429ceSEric Joyner hw->phy.ops.release(hw);
1694c80429ceSEric Joyner if (ret_val)
1695c80429ceSEric Joyner return ret_val;
1696c80429ceSEric Joyner
1697c80429ceSEric Joyner }
1698c80429ceSEric Joyner }
1699c80429ceSEric Joyner }
1700c80429ceSEric Joyner
1701c80429ceSEric Joyner /* I217 Packet Loss issue:
1702c80429ceSEric Joyner * ensure that FEXTNVM4 Beacon Duration is set correctly
1703c80429ceSEric Joyner * on power up.
1704c80429ceSEric Joyner * Set the Beacon Duration for I217 to 8 usec
1705c80429ceSEric Joyner */
1706295df609SEric Joyner if (hw->mac.type >= e1000_pch_lpt) {
1707c80429ceSEric Joyner u32 mac_reg;
1708c80429ceSEric Joyner
1709c80429ceSEric Joyner mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM4);
1710c80429ceSEric Joyner mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK;
1711c80429ceSEric Joyner mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_8USEC;
1712c80429ceSEric Joyner E1000_WRITE_REG(hw, E1000_FEXTNVM4, mac_reg);
17136ab6bfe3SJack F Vogel }
17146ab6bfe3SJack F Vogel
17156ab6bfe3SJack F Vogel /* Work-around I218 hang issue */
17166ab6bfe3SJack F Vogel if ((hw->device_id == E1000_DEV_ID_PCH_LPTLP_I218_LM) ||
17178cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_LPTLP_I218_V) ||
17188cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_I218_LM3) ||
17198cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_I218_V3)) {
17206ab6bfe3SJack F Vogel ret_val = e1000_k1_workaround_lpt_lp(hw, link);
17216ab6bfe3SJack F Vogel if (ret_val)
17226ab6bfe3SJack F Vogel return ret_val;
17236ab6bfe3SJack F Vogel }
1724295df609SEric Joyner if (hw->mac.type >= e1000_pch_lpt) {
1725e373323fSSean Bruno /* Set platform power management values for
1726e373323fSSean Bruno * Latency Tolerance Reporting (LTR)
1727e373323fSSean Bruno * Optimized Buffer Flush/Fill (OBFF)
1728e373323fSSean Bruno */
1729e373323fSSean Bruno ret_val = e1000_platform_pm_pch_lpt(hw, link);
1730e373323fSSean Bruno if (ret_val)
1731e373323fSSean Bruno return ret_val;
1732e373323fSSean Bruno }
17336ab6bfe3SJack F Vogel /* Clear link partner's EEE ability */
17346ab6bfe3SJack F Vogel hw->dev_spec.ich8lan.eee_lp_ability = 0;
17356ab6bfe3SJack F Vogel
1736295df609SEric Joyner if (hw->mac.type >= e1000_pch_lpt) {
1737c80429ceSEric Joyner u32 fextnvm6 = E1000_READ_REG(hw, E1000_FEXTNVM6);
1738c80429ceSEric Joyner
1739295df609SEric Joyner if (hw->mac.type == e1000_pch_spt) {
1740295df609SEric Joyner /* FEXTNVM6 K1-off workaround - for SPT only */
1741295df609SEric Joyner u32 pcieanacfg = E1000_READ_REG(hw, E1000_PCIEANACFG);
1742295df609SEric Joyner
1743295df609SEric Joyner if (pcieanacfg & E1000_FEXTNVM6_K1_OFF_ENABLE)
1744c80429ceSEric Joyner fextnvm6 |= E1000_FEXTNVM6_K1_OFF_ENABLE;
1745c80429ceSEric Joyner else
1746c80429ceSEric Joyner fextnvm6 &= ~E1000_FEXTNVM6_K1_OFF_ENABLE;
1747295df609SEric Joyner }
1748295df609SEric Joyner
17491bbdc25fSKevin Bowling if (hw->dev_spec.ich8lan.disable_k1_off == true)
1750295df609SEric Joyner fextnvm6 &= ~E1000_FEXTNVM6_K1_OFF_ENABLE;
1751c80429ceSEric Joyner
1752c80429ceSEric Joyner E1000_WRITE_REG(hw, E1000_FEXTNVM6, fextnvm6);
1753d5ad2f2aSWenzhuo Lu
1754d5ad2f2aSWenzhuo Lu /* Configure K0s minimum time */
1755d5ad2f2aSWenzhuo Lu e1000_configure_k0s_lpt(hw, K1_ENTRY_LATENCY, K1_MIN_TIME);
1756c80429ceSEric Joyner }
1757c80429ceSEric Joyner
17584edd8523SJack F Vogel if (!link)
17596ab6bfe3SJack F Vogel return E1000_SUCCESS; /* No link detected */
17604edd8523SJack F Vogel
17611bbdc25fSKevin Bowling mac->get_link_status = false;
17624edd8523SJack F Vogel
17634dab5c37SJack F Vogel switch (hw->mac.type) {
17644dab5c37SJack F Vogel case e1000_pch2lan:
17654dab5c37SJack F Vogel ret_val = e1000_k1_workaround_lv(hw);
17664dab5c37SJack F Vogel if (ret_val)
17676ab6bfe3SJack F Vogel return ret_val;
1768e05d9788SKevin Bowling /* FALLTHROUGH */
17694dab5c37SJack F Vogel case e1000_pchlan:
17704edd8523SJack F Vogel if (hw->phy.type == e1000_phy_82578) {
17714edd8523SJack F Vogel ret_val = e1000_link_stall_workaround_hv(hw);
17724edd8523SJack F Vogel if (ret_val)
17736ab6bfe3SJack F Vogel return ret_val;
17744edd8523SJack F Vogel }
17754edd8523SJack F Vogel
17766ab6bfe3SJack F Vogel /* Workaround for PCHx parts in half-duplex:
17774dab5c37SJack F Vogel * Set the number of preambles removed from the packet
17784dab5c37SJack F Vogel * when it is passed from the PHY to the MAC to prevent
17794dab5c37SJack F Vogel * the MAC from misinterpreting the packet type.
17804dab5c37SJack F Vogel */
17814dab5c37SJack F Vogel hw->phy.ops.read_reg(hw, HV_KMRN_FIFO_CTRLSTA, &phy_reg);
17824dab5c37SJack F Vogel phy_reg &= ~HV_KMRN_FIFO_CTRLSTA_PREAMBLE_MASK;
17834dab5c37SJack F Vogel
17844dab5c37SJack F Vogel if ((E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_FD) !=
17854dab5c37SJack F Vogel E1000_STATUS_FD)
17864dab5c37SJack F Vogel phy_reg |= (1 << HV_KMRN_FIFO_CTRLSTA_PREAMBLE_SHIFT);
17874dab5c37SJack F Vogel
17884dab5c37SJack F Vogel hw->phy.ops.write_reg(hw, HV_KMRN_FIFO_CTRLSTA, phy_reg);
17894dab5c37SJack F Vogel break;
17904dab5c37SJack F Vogel default:
17914dab5c37SJack F Vogel break;
17927d9119bdSJack F Vogel }
17937d9119bdSJack F Vogel
17946ab6bfe3SJack F Vogel /* Check if there was DownShift, must be checked
17954edd8523SJack F Vogel * immediately after link-up
17964edd8523SJack F Vogel */
17974edd8523SJack F Vogel e1000_check_downshift_generic(hw);
17984edd8523SJack F Vogel
17997d9119bdSJack F Vogel /* Enable/Disable EEE after link up */
18007609433eSJack F Vogel if (hw->phy.type > e1000_phy_82579) {
18017d9119bdSJack F Vogel ret_val = e1000_set_eee_pchlan(hw);
18027d9119bdSJack F Vogel if (ret_val)
18036ab6bfe3SJack F Vogel return ret_val;
18047609433eSJack F Vogel }
18057d9119bdSJack F Vogel
18066ab6bfe3SJack F Vogel /* If we are forcing speed/duplex, then we simply return since
18074edd8523SJack F Vogel * we have already determined whether we have link or not.
18084edd8523SJack F Vogel */
18096ab6bfe3SJack F Vogel if (!mac->autoneg)
18106ab6bfe3SJack F Vogel return -E1000_ERR_CONFIG;
18114edd8523SJack F Vogel
18126ab6bfe3SJack F Vogel /* Auto-Neg is enabled. Auto Speed Detection takes care
18134edd8523SJack F Vogel * of MAC speed/duplex configuration. So we only need to
18144edd8523SJack F Vogel * configure Collision Distance in the MAC.
18154edd8523SJack F Vogel */
18166ab6bfe3SJack F Vogel mac->ops.config_collision_dist(hw);
18174edd8523SJack F Vogel
18186ab6bfe3SJack F Vogel /* Configure Flow Control now that Auto-Neg has completed.
18194edd8523SJack F Vogel * First, we need to restore the desired flow control
18204edd8523SJack F Vogel * settings because we may have had to re-autoneg with a
18214edd8523SJack F Vogel * different link partner.
18224edd8523SJack F Vogel */
18234edd8523SJack F Vogel ret_val = e1000_config_fc_after_link_up_generic(hw);
18244edd8523SJack F Vogel if (ret_val)
18254edd8523SJack F Vogel DEBUGOUT("Error configuring flow control\n");
18264edd8523SJack F Vogel
18274edd8523SJack F Vogel return ret_val;
18284edd8523SJack F Vogel }
18294edd8523SJack F Vogel
18304edd8523SJack F Vogel /**
18318cfa0ad2SJack F Vogel * e1000_init_function_pointers_ich8lan - Initialize ICH8 function pointers
18328cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
18338cfa0ad2SJack F Vogel *
18348cfa0ad2SJack F Vogel * Initialize family-specific function pointers for PHY, MAC, and NVM.
18358cfa0ad2SJack F Vogel **/
e1000_init_function_pointers_ich8lan(struct e1000_hw * hw)18368cfa0ad2SJack F Vogel void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw)
18378cfa0ad2SJack F Vogel {
18388cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_function_pointers_ich8lan");
18398cfa0ad2SJack F Vogel
18408cfa0ad2SJack F Vogel hw->mac.ops.init_params = e1000_init_mac_params_ich8lan;
18418cfa0ad2SJack F Vogel hw->nvm.ops.init_params = e1000_init_nvm_params_ich8lan;
18429d81738fSJack F Vogel switch (hw->mac.type) {
18439d81738fSJack F Vogel case e1000_ich8lan:
18449d81738fSJack F Vogel case e1000_ich9lan:
18459d81738fSJack F Vogel case e1000_ich10lan:
18468cfa0ad2SJack F Vogel hw->phy.ops.init_params = e1000_init_phy_params_ich8lan;
18479d81738fSJack F Vogel break;
18489d81738fSJack F Vogel case e1000_pchlan:
18497d9119bdSJack F Vogel case e1000_pch2lan:
18506ab6bfe3SJack F Vogel case e1000_pch_lpt:
1851c80429ceSEric Joyner case e1000_pch_spt:
18526fe4c0a0SSean Bruno case e1000_pch_cnp:
185359690eabSKevin Bowling case e1000_pch_tgp:
185459690eabSKevin Bowling case e1000_pch_adp:
185559690eabSKevin Bowling case e1000_pch_mtp:
1856*905ae588SKevin Bowling case e1000_pch_ptp:
18579d81738fSJack F Vogel hw->phy.ops.init_params = e1000_init_phy_params_pchlan;
18589d81738fSJack F Vogel break;
18599d81738fSJack F Vogel default:
18609d81738fSJack F Vogel break;
18619d81738fSJack F Vogel }
18628cfa0ad2SJack F Vogel }
18638cfa0ad2SJack F Vogel
18648cfa0ad2SJack F Vogel /**
18654edd8523SJack F Vogel * e1000_acquire_nvm_ich8lan - Acquire NVM mutex
18664edd8523SJack F Vogel * @hw: pointer to the HW structure
18674edd8523SJack F Vogel *
18684edd8523SJack F Vogel * Acquires the mutex for performing NVM operations.
18694edd8523SJack F Vogel **/
e1000_acquire_nvm_ich8lan(struct e1000_hw * hw)18704edd8523SJack F Vogel static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw)
18714edd8523SJack F Vogel {
18724edd8523SJack F Vogel DEBUGFUNC("e1000_acquire_nvm_ich8lan");
18734edd8523SJack F Vogel
1874d5210708SMatt Macy ASSERT_CTX_LOCK_HELD(hw);
18754edd8523SJack F Vogel
18764edd8523SJack F Vogel return E1000_SUCCESS;
18774edd8523SJack F Vogel }
18784edd8523SJack F Vogel
18794edd8523SJack F Vogel /**
18804edd8523SJack F Vogel * e1000_release_nvm_ich8lan - Release NVM mutex
18814edd8523SJack F Vogel * @hw: pointer to the HW structure
18824edd8523SJack F Vogel *
18834edd8523SJack F Vogel * Releases the mutex used while performing NVM operations.
18844edd8523SJack F Vogel **/
e1000_release_nvm_ich8lan(struct e1000_hw * hw)18854edd8523SJack F Vogel static void e1000_release_nvm_ich8lan(struct e1000_hw *hw)
18864edd8523SJack F Vogel {
18874edd8523SJack F Vogel DEBUGFUNC("e1000_release_nvm_ich8lan");
18884edd8523SJack F Vogel
1889d5210708SMatt Macy ASSERT_CTX_LOCK_HELD(hw);
18904edd8523SJack F Vogel }
18914edd8523SJack F Vogel
18924edd8523SJack F Vogel /**
18938cfa0ad2SJack F Vogel * e1000_acquire_swflag_ich8lan - Acquire software control flag
18948cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
18958cfa0ad2SJack F Vogel *
18964edd8523SJack F Vogel * Acquires the software control flag for performing PHY and select
18974edd8523SJack F Vogel * MAC CSR accesses.
18988cfa0ad2SJack F Vogel **/
e1000_acquire_swflag_ich8lan(struct e1000_hw * hw)18998cfa0ad2SJack F Vogel static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
19008cfa0ad2SJack F Vogel {
19018cfa0ad2SJack F Vogel u32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT;
19028cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS;
19038cfa0ad2SJack F Vogel
19048cfa0ad2SJack F Vogel DEBUGFUNC("e1000_acquire_swflag_ich8lan");
19058cfa0ad2SJack F Vogel
1906d5210708SMatt Macy ASSERT_CTX_LOCK_HELD(hw);
19074edd8523SJack F Vogel
19088cfa0ad2SJack F Vogel while (timeout) {
19098cfa0ad2SJack F Vogel extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
19104edd8523SJack F Vogel if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG))
19118cfa0ad2SJack F Vogel break;
19124edd8523SJack F Vogel
19138cfa0ad2SJack F Vogel msec_delay_irq(1);
19148cfa0ad2SJack F Vogel timeout--;
19158cfa0ad2SJack F Vogel }
19168cfa0ad2SJack F Vogel
19178cfa0ad2SJack F Vogel if (!timeout) {
19184dab5c37SJack F Vogel DEBUGOUT("SW has already locked the resource.\n");
19194edd8523SJack F Vogel ret_val = -E1000_ERR_CONFIG;
19204edd8523SJack F Vogel goto out;
19214edd8523SJack F Vogel }
19224edd8523SJack F Vogel
19234edd8523SJack F Vogel timeout = SW_FLAG_TIMEOUT;
19244edd8523SJack F Vogel
19254edd8523SJack F Vogel extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
19264edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
19274edd8523SJack F Vogel
19284edd8523SJack F Vogel while (timeout) {
19294edd8523SJack F Vogel extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
19304edd8523SJack F Vogel if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
19314edd8523SJack F Vogel break;
19324edd8523SJack F Vogel
19334edd8523SJack F Vogel msec_delay_irq(1);
19344edd8523SJack F Vogel timeout--;
19354edd8523SJack F Vogel }
19364edd8523SJack F Vogel
19374edd8523SJack F Vogel if (!timeout) {
19384dab5c37SJack F Vogel DEBUGOUT2("Failed to acquire the semaphore, FW or HW has it: FWSM=0x%8.8x EXTCNF_CTRL=0x%8.8x)\n",
19394dab5c37SJack F Vogel E1000_READ_REG(hw, E1000_FWSM), extcnf_ctrl);
19408cfa0ad2SJack F Vogel extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
19418cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
19428cfa0ad2SJack F Vogel ret_val = -E1000_ERR_CONFIG;
19438cfa0ad2SJack F Vogel goto out;
19448cfa0ad2SJack F Vogel }
19458cfa0ad2SJack F Vogel
19468cfa0ad2SJack F Vogel out:
19478cfa0ad2SJack F Vogel return ret_val;
19488cfa0ad2SJack F Vogel }
19498cfa0ad2SJack F Vogel
19508cfa0ad2SJack F Vogel /**
19518cfa0ad2SJack F Vogel * e1000_release_swflag_ich8lan - Release software control flag
19528cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
19538cfa0ad2SJack F Vogel *
19544edd8523SJack F Vogel * Releases the software control flag for performing PHY and select
19554edd8523SJack F Vogel * MAC CSR accesses.
19568cfa0ad2SJack F Vogel **/
e1000_release_swflag_ich8lan(struct e1000_hw * hw)19578cfa0ad2SJack F Vogel static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
19588cfa0ad2SJack F Vogel {
19598cfa0ad2SJack F Vogel u32 extcnf_ctrl;
19608cfa0ad2SJack F Vogel
19618cfa0ad2SJack F Vogel DEBUGFUNC("e1000_release_swflag_ich8lan");
19628cfa0ad2SJack F Vogel
19638cfa0ad2SJack F Vogel extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
1964730d3130SJack F Vogel
1965730d3130SJack F Vogel if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) {
19668cfa0ad2SJack F Vogel extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
19678cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
1968730d3130SJack F Vogel } else {
1969730d3130SJack F Vogel DEBUGOUT("Semaphore unexpectedly released by sw/fw/hw\n");
1970730d3130SJack F Vogel }
19718cfa0ad2SJack F Vogel }
19728cfa0ad2SJack F Vogel
19738cfa0ad2SJack F Vogel /**
19748cfa0ad2SJack F Vogel * e1000_check_mng_mode_ich8lan - Checks management mode
19758cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
19768cfa0ad2SJack F Vogel *
19777d9119bdSJack F Vogel * This checks if the adapter has any manageability enabled.
19788cfa0ad2SJack F Vogel * This is a function pointer entry point only called by read/write
19798cfa0ad2SJack F Vogel * routines for the PHY and NVM parts.
19808cfa0ad2SJack F Vogel **/
e1000_check_mng_mode_ich8lan(struct e1000_hw * hw)19818cfa0ad2SJack F Vogel static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw)
19828cfa0ad2SJack F Vogel {
19838cfa0ad2SJack F Vogel u32 fwsm;
19848cfa0ad2SJack F Vogel
19858cfa0ad2SJack F Vogel DEBUGFUNC("e1000_check_mng_mode_ich8lan");
19868cfa0ad2SJack F Vogel
19878cfa0ad2SJack F Vogel fwsm = E1000_READ_REG(hw, E1000_FWSM);
19888cfa0ad2SJack F Vogel
19898cc64f1eSJack F Vogel return (fwsm & E1000_ICH_FWSM_FW_VALID) &&
19907d9119bdSJack F Vogel ((fwsm & E1000_FWSM_MODE_MASK) ==
19918cc64f1eSJack F Vogel (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
19927d9119bdSJack F Vogel }
19937d9119bdSJack F Vogel
19947d9119bdSJack F Vogel /**
19957d9119bdSJack F Vogel * e1000_check_mng_mode_pchlan - Checks management mode
19967d9119bdSJack F Vogel * @hw: pointer to the HW structure
19977d9119bdSJack F Vogel *
19987d9119bdSJack F Vogel * This checks if the adapter has iAMT enabled.
19997d9119bdSJack F Vogel * This is a function pointer entry point only called by read/write
20007d9119bdSJack F Vogel * routines for the PHY and NVM parts.
20017d9119bdSJack F Vogel **/
e1000_check_mng_mode_pchlan(struct e1000_hw * hw)20027d9119bdSJack F Vogel static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw)
20037d9119bdSJack F Vogel {
20047d9119bdSJack F Vogel u32 fwsm;
20057d9119bdSJack F Vogel
20067d9119bdSJack F Vogel DEBUGFUNC("e1000_check_mng_mode_pchlan");
20077d9119bdSJack F Vogel
20087d9119bdSJack F Vogel fwsm = E1000_READ_REG(hw, E1000_FWSM);
20097d9119bdSJack F Vogel
20107d9119bdSJack F Vogel return (fwsm & E1000_ICH_FWSM_FW_VALID) &&
20117d9119bdSJack F Vogel (fwsm & (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
20127d9119bdSJack F Vogel }
20137d9119bdSJack F Vogel
20147d9119bdSJack F Vogel /**
20157d9119bdSJack F Vogel * e1000_rar_set_pch2lan - Set receive address register
20167d9119bdSJack F Vogel * @hw: pointer to the HW structure
20177d9119bdSJack F Vogel * @addr: pointer to the receive address
20187d9119bdSJack F Vogel * @index: receive address array register
20197d9119bdSJack F Vogel *
20207d9119bdSJack F Vogel * Sets the receive address array register at index to the address passed
20217d9119bdSJack F Vogel * in by addr. For 82579, RAR[0] is the base address register that is to
20227d9119bdSJack F Vogel * contain the MAC address but RAR[1-6] are reserved for manageability (ME).
20237d9119bdSJack F Vogel * Use SHRA[0-3] in place of those reserved for ME.
20247d9119bdSJack F Vogel **/
e1000_rar_set_pch2lan(struct e1000_hw * hw,u8 * addr,u32 index)20258cc64f1eSJack F Vogel static int e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index)
20267d9119bdSJack F Vogel {
20277d9119bdSJack F Vogel u32 rar_low, rar_high;
20287d9119bdSJack F Vogel
20297d9119bdSJack F Vogel DEBUGFUNC("e1000_rar_set_pch2lan");
20307d9119bdSJack F Vogel
20316ab6bfe3SJack F Vogel /* HW expects these in little endian so we reverse the byte order
20327d9119bdSJack F Vogel * from network order (big endian) to little endian
20337d9119bdSJack F Vogel */
20347d9119bdSJack F Vogel rar_low = ((u32) addr[0] |
20357d9119bdSJack F Vogel ((u32) addr[1] << 8) |
20367d9119bdSJack F Vogel ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
20377d9119bdSJack F Vogel
20387d9119bdSJack F Vogel rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
20397d9119bdSJack F Vogel
20407d9119bdSJack F Vogel /* If MAC address zero, no need to set the AV bit */
20417d9119bdSJack F Vogel if (rar_low || rar_high)
20427d9119bdSJack F Vogel rar_high |= E1000_RAH_AV;
20437d9119bdSJack F Vogel
20447d9119bdSJack F Vogel if (index == 0) {
20457d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_RAL(index), rar_low);
20467d9119bdSJack F Vogel E1000_WRITE_FLUSH(hw);
20477d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_RAH(index), rar_high);
20487d9119bdSJack F Vogel E1000_WRITE_FLUSH(hw);
20498cc64f1eSJack F Vogel return E1000_SUCCESS;
20507d9119bdSJack F Vogel }
20517d9119bdSJack F Vogel
20527609433eSJack F Vogel /* RAR[1-6] are owned by manageability. Skip those and program the
20537609433eSJack F Vogel * next address into the SHRA register array.
20547609433eSJack F Vogel */
20558cc64f1eSJack F Vogel if (index < (u32) (hw->mac.rar_entry_count)) {
20566ab6bfe3SJack F Vogel s32 ret_val;
20576ab6bfe3SJack F Vogel
20586ab6bfe3SJack F Vogel ret_val = e1000_acquire_swflag_ich8lan(hw);
20596ab6bfe3SJack F Vogel if (ret_val)
20606ab6bfe3SJack F Vogel goto out;
20616ab6bfe3SJack F Vogel
20627d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_SHRAL(index - 1), rar_low);
20637d9119bdSJack F Vogel E1000_WRITE_FLUSH(hw);
20647d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_SHRAH(index - 1), rar_high);
20657d9119bdSJack F Vogel E1000_WRITE_FLUSH(hw);
20667d9119bdSJack F Vogel
20676ab6bfe3SJack F Vogel e1000_release_swflag_ich8lan(hw);
20686ab6bfe3SJack F Vogel
20697d9119bdSJack F Vogel /* verify the register updates */
20707d9119bdSJack F Vogel if ((E1000_READ_REG(hw, E1000_SHRAL(index - 1)) == rar_low) &&
20717d9119bdSJack F Vogel (E1000_READ_REG(hw, E1000_SHRAH(index - 1)) == rar_high))
20728cc64f1eSJack F Vogel return E1000_SUCCESS;
20737d9119bdSJack F Vogel
20747d9119bdSJack F Vogel DEBUGOUT2("SHRA[%d] might be locked by ME - FWSM=0x%8.8x\n",
20757d9119bdSJack F Vogel (index - 1), E1000_READ_REG(hw, E1000_FWSM));
20767d9119bdSJack F Vogel }
20777d9119bdSJack F Vogel
20786ab6bfe3SJack F Vogel out:
20796ab6bfe3SJack F Vogel DEBUGOUT1("Failed to write receive address at index %d\n", index);
20808cc64f1eSJack F Vogel return -E1000_ERR_CONFIG;
20816ab6bfe3SJack F Vogel }
20826ab6bfe3SJack F Vogel
20836ab6bfe3SJack F Vogel /**
20846ab6bfe3SJack F Vogel * e1000_rar_set_pch_lpt - Set receive address registers
20856ab6bfe3SJack F Vogel * @hw: pointer to the HW structure
20866ab6bfe3SJack F Vogel * @addr: pointer to the receive address
20876ab6bfe3SJack F Vogel * @index: receive address array register
20886ab6bfe3SJack F Vogel *
20896ab6bfe3SJack F Vogel * Sets the receive address register array at index to the address passed
20906ab6bfe3SJack F Vogel * in by addr. For LPT, RAR[0] is the base address register that is to
20916ab6bfe3SJack F Vogel * contain the MAC address. SHRA[0-10] are the shared receive address
20926ab6bfe3SJack F Vogel * registers that are shared between the Host and manageability engine (ME).
20936ab6bfe3SJack F Vogel **/
e1000_rar_set_pch_lpt(struct e1000_hw * hw,u8 * addr,u32 index)20948cc64f1eSJack F Vogel static int e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index)
20956ab6bfe3SJack F Vogel {
20966ab6bfe3SJack F Vogel u32 rar_low, rar_high;
20976ab6bfe3SJack F Vogel u32 wlock_mac;
20986ab6bfe3SJack F Vogel
20996ab6bfe3SJack F Vogel DEBUGFUNC("e1000_rar_set_pch_lpt");
21006ab6bfe3SJack F Vogel
21016ab6bfe3SJack F Vogel /* HW expects these in little endian so we reverse the byte order
21026ab6bfe3SJack F Vogel * from network order (big endian) to little endian
21036ab6bfe3SJack F Vogel */
21046ab6bfe3SJack F Vogel rar_low = ((u32) addr[0] | ((u32) addr[1] << 8) |
21056ab6bfe3SJack F Vogel ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
21066ab6bfe3SJack F Vogel
21076ab6bfe3SJack F Vogel rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
21086ab6bfe3SJack F Vogel
21096ab6bfe3SJack F Vogel /* If MAC address zero, no need to set the AV bit */
21106ab6bfe3SJack F Vogel if (rar_low || rar_high)
21116ab6bfe3SJack F Vogel rar_high |= E1000_RAH_AV;
21126ab6bfe3SJack F Vogel
21136ab6bfe3SJack F Vogel if (index == 0) {
21146ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_RAL(index), rar_low);
21156ab6bfe3SJack F Vogel E1000_WRITE_FLUSH(hw);
21166ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_RAH(index), rar_high);
21176ab6bfe3SJack F Vogel E1000_WRITE_FLUSH(hw);
21188cc64f1eSJack F Vogel return E1000_SUCCESS;
21196ab6bfe3SJack F Vogel }
21206ab6bfe3SJack F Vogel
21216ab6bfe3SJack F Vogel /* The manageability engine (ME) can lock certain SHRAR registers that
21226ab6bfe3SJack F Vogel * it is using - those registers are unavailable for use.
21236ab6bfe3SJack F Vogel */
21246ab6bfe3SJack F Vogel if (index < hw->mac.rar_entry_count) {
21256ab6bfe3SJack F Vogel wlock_mac = E1000_READ_REG(hw, E1000_FWSM) &
21266ab6bfe3SJack F Vogel E1000_FWSM_WLOCK_MAC_MASK;
21276ab6bfe3SJack F Vogel wlock_mac >>= E1000_FWSM_WLOCK_MAC_SHIFT;
21286ab6bfe3SJack F Vogel
21296ab6bfe3SJack F Vogel /* Check if all SHRAR registers are locked */
21306ab6bfe3SJack F Vogel if (wlock_mac == 1)
21316ab6bfe3SJack F Vogel goto out;
21326ab6bfe3SJack F Vogel
21336ab6bfe3SJack F Vogel if ((wlock_mac == 0) || (index <= wlock_mac)) {
21346ab6bfe3SJack F Vogel s32 ret_val;
21356ab6bfe3SJack F Vogel
21366ab6bfe3SJack F Vogel ret_val = e1000_acquire_swflag_ich8lan(hw);
21376ab6bfe3SJack F Vogel
21386ab6bfe3SJack F Vogel if (ret_val)
21396ab6bfe3SJack F Vogel goto out;
21406ab6bfe3SJack F Vogel
21416ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_SHRAL_PCH_LPT(index - 1),
21426ab6bfe3SJack F Vogel rar_low);
21436ab6bfe3SJack F Vogel E1000_WRITE_FLUSH(hw);
21446ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_SHRAH_PCH_LPT(index - 1),
21456ab6bfe3SJack F Vogel rar_high);
21466ab6bfe3SJack F Vogel E1000_WRITE_FLUSH(hw);
21476ab6bfe3SJack F Vogel
21486ab6bfe3SJack F Vogel e1000_release_swflag_ich8lan(hw);
21496ab6bfe3SJack F Vogel
21506ab6bfe3SJack F Vogel /* verify the register updates */
21516ab6bfe3SJack F Vogel if ((E1000_READ_REG(hw, E1000_SHRAL_PCH_LPT(index - 1)) == rar_low) &&
21526ab6bfe3SJack F Vogel (E1000_READ_REG(hw, E1000_SHRAH_PCH_LPT(index - 1)) == rar_high))
21538cc64f1eSJack F Vogel return E1000_SUCCESS;
21546ab6bfe3SJack F Vogel }
21556ab6bfe3SJack F Vogel }
21566ab6bfe3SJack F Vogel
21576ab6bfe3SJack F Vogel out:
21587d9119bdSJack F Vogel DEBUGOUT1("Failed to write receive address at index %d\n", index);
21598cc64f1eSJack F Vogel return -E1000_ERR_CONFIG;
21608cfa0ad2SJack F Vogel }
21618cfa0ad2SJack F Vogel
21628cfa0ad2SJack F Vogel /**
2163730d3130SJack F Vogel * e1000_update_mc_addr_list_pch2lan - Update Multicast addresses
2164730d3130SJack F Vogel * @hw: pointer to the HW structure
2165730d3130SJack F Vogel * @mc_addr_list: array of multicast addresses to program
2166730d3130SJack F Vogel * @mc_addr_count: number of multicast addresses to program
2167730d3130SJack F Vogel *
2168730d3130SJack F Vogel * Updates entire Multicast Table Array of the PCH2 MAC and PHY.
2169730d3130SJack F Vogel * The caller must have a packed mc_addr_list of multicast addresses.
2170730d3130SJack F Vogel **/
e1000_update_mc_addr_list_pch2lan(struct e1000_hw * hw,u8 * mc_addr_list,u32 mc_addr_count)2171730d3130SJack F Vogel static void e1000_update_mc_addr_list_pch2lan(struct e1000_hw *hw,
2172730d3130SJack F Vogel u8 *mc_addr_list,
2173730d3130SJack F Vogel u32 mc_addr_count)
2174730d3130SJack F Vogel {
21754dab5c37SJack F Vogel u16 phy_reg = 0;
2176730d3130SJack F Vogel int i;
21774dab5c37SJack F Vogel s32 ret_val;
2178730d3130SJack F Vogel
2179730d3130SJack F Vogel DEBUGFUNC("e1000_update_mc_addr_list_pch2lan");
2180730d3130SJack F Vogel
2181730d3130SJack F Vogel e1000_update_mc_addr_list_generic(hw, mc_addr_list, mc_addr_count);
2182730d3130SJack F Vogel
21834dab5c37SJack F Vogel ret_val = hw->phy.ops.acquire(hw);
21844dab5c37SJack F Vogel if (ret_val)
21854dab5c37SJack F Vogel return;
21864dab5c37SJack F Vogel
21874dab5c37SJack F Vogel ret_val = e1000_enable_phy_wakeup_reg_access_bm(hw, &phy_reg);
21884dab5c37SJack F Vogel if (ret_val)
21894dab5c37SJack F Vogel goto release;
21904dab5c37SJack F Vogel
2191730d3130SJack F Vogel for (i = 0; i < hw->mac.mta_reg_count; i++) {
21924dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, BM_MTA(i),
21934dab5c37SJack F Vogel (u16)(hw->mac.mta_shadow[i] &
21944dab5c37SJack F Vogel 0xFFFF));
21954dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, (BM_MTA(i) + 1),
2196730d3130SJack F Vogel (u16)((hw->mac.mta_shadow[i] >> 16) &
2197730d3130SJack F Vogel 0xFFFF));
2198730d3130SJack F Vogel }
21994dab5c37SJack F Vogel
22004dab5c37SJack F Vogel e1000_disable_phy_wakeup_reg_access_bm(hw, &phy_reg);
22014dab5c37SJack F Vogel
22024dab5c37SJack F Vogel release:
22034dab5c37SJack F Vogel hw->phy.ops.release(hw);
2204730d3130SJack F Vogel }
2205730d3130SJack F Vogel
2206730d3130SJack F Vogel /**
22078cfa0ad2SJack F Vogel * e1000_check_reset_block_ich8lan - Check if PHY reset is blocked
22088cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
22098cfa0ad2SJack F Vogel *
22108cfa0ad2SJack F Vogel * Checks if firmware is blocking the reset of the PHY.
22118cfa0ad2SJack F Vogel * This is a function pointer entry point only called by
22128cfa0ad2SJack F Vogel * reset routines.
22138cfa0ad2SJack F Vogel **/
e1000_check_reset_block_ich8lan(struct e1000_hw * hw)22148cfa0ad2SJack F Vogel static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
22158cfa0ad2SJack F Vogel {
22168cfa0ad2SJack F Vogel u32 fwsm;
22171bbdc25fSKevin Bowling bool blocked = false;
22187609433eSJack F Vogel int i = 0;
22198cfa0ad2SJack F Vogel
22208cfa0ad2SJack F Vogel DEBUGFUNC("e1000_check_reset_block_ich8lan");
22218cfa0ad2SJack F Vogel
22227609433eSJack F Vogel do {
22238cfa0ad2SJack F Vogel fwsm = E1000_READ_REG(hw, E1000_FWSM);
22247609433eSJack F Vogel if (!(fwsm & E1000_ICH_FWSM_RSPCIPHY)) {
22251bbdc25fSKevin Bowling blocked = true;
22267609433eSJack F Vogel msec_delay(10);
22277609433eSJack F Vogel continue;
22287609433eSJack F Vogel }
22291bbdc25fSKevin Bowling blocked = false;
2230c80429ceSEric Joyner } while (blocked && (i++ < 30));
22317609433eSJack F Vogel return blocked ? E1000_BLK_PHY_RESET : E1000_SUCCESS;
22328cfa0ad2SJack F Vogel }
22338cfa0ad2SJack F Vogel
22348cfa0ad2SJack F Vogel /**
22357d9119bdSJack F Vogel * e1000_write_smbus_addr - Write SMBus address to PHY needed during Sx states
22367d9119bdSJack F Vogel * @hw: pointer to the HW structure
22377d9119bdSJack F Vogel *
22387d9119bdSJack F Vogel * Assumes semaphore already acquired.
22397d9119bdSJack F Vogel *
22407d9119bdSJack F Vogel **/
e1000_write_smbus_addr(struct e1000_hw * hw)22417d9119bdSJack F Vogel static s32 e1000_write_smbus_addr(struct e1000_hw *hw)
22427d9119bdSJack F Vogel {
22437d9119bdSJack F Vogel u16 phy_data;
22447d9119bdSJack F Vogel u32 strap = E1000_READ_REG(hw, E1000_STRAP);
22456ab6bfe3SJack F Vogel u32 freq = (strap & E1000_STRAP_SMT_FREQ_MASK) >>
22466ab6bfe3SJack F Vogel E1000_STRAP_SMT_FREQ_SHIFT;
22476ab6bfe3SJack F Vogel s32 ret_val;
22487d9119bdSJack F Vogel
22497d9119bdSJack F Vogel strap &= E1000_STRAP_SMBUS_ADDRESS_MASK;
22507d9119bdSJack F Vogel
22517d9119bdSJack F Vogel ret_val = e1000_read_phy_reg_hv_locked(hw, HV_SMB_ADDR, &phy_data);
22527d9119bdSJack F Vogel if (ret_val)
22536ab6bfe3SJack F Vogel return ret_val;
22547d9119bdSJack F Vogel
22557d9119bdSJack F Vogel phy_data &= ~HV_SMB_ADDR_MASK;
22567d9119bdSJack F Vogel phy_data |= (strap >> E1000_STRAP_SMBUS_ADDRESS_SHIFT);
22577d9119bdSJack F Vogel phy_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID;
22587d9119bdSJack F Vogel
22596ab6bfe3SJack F Vogel if (hw->phy.type == e1000_phy_i217) {
22606ab6bfe3SJack F Vogel /* Restore SMBus frequency */
22616ab6bfe3SJack F Vogel if (freq--) {
22626ab6bfe3SJack F Vogel phy_data &= ~HV_SMB_ADDR_FREQ_MASK;
22636ab6bfe3SJack F Vogel phy_data |= (freq & (1 << 0)) <<
22646ab6bfe3SJack F Vogel HV_SMB_ADDR_FREQ_LOW_SHIFT;
22656ab6bfe3SJack F Vogel phy_data |= (freq & (1 << 1)) <<
22666ab6bfe3SJack F Vogel (HV_SMB_ADDR_FREQ_HIGH_SHIFT - 1);
22676ab6bfe3SJack F Vogel } else {
22686ab6bfe3SJack F Vogel DEBUGOUT("Unsupported SMB frequency in PHY\n");
22696ab6bfe3SJack F Vogel }
22706ab6bfe3SJack F Vogel }
22716ab6bfe3SJack F Vogel
22726ab6bfe3SJack F Vogel return e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR, phy_data);
22737d9119bdSJack F Vogel }
22747d9119bdSJack F Vogel
22757d9119bdSJack F Vogel /**
22764edd8523SJack F Vogel * e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration
22774edd8523SJack F Vogel * @hw: pointer to the HW structure
22784edd8523SJack F Vogel *
22794edd8523SJack F Vogel * SW should configure the LCD from the NVM extended configuration region
22804edd8523SJack F Vogel * as a workaround for certain parts.
22814edd8523SJack F Vogel **/
e1000_sw_lcd_config_ich8lan(struct e1000_hw * hw)22824edd8523SJack F Vogel static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
22834edd8523SJack F Vogel {
22844edd8523SJack F Vogel struct e1000_phy_info *phy = &hw->phy;
22854edd8523SJack F Vogel u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask;
2286a69ed8dfSJack F Vogel s32 ret_val = E1000_SUCCESS;
22874edd8523SJack F Vogel u16 word_addr, reg_data, reg_addr, phy_page = 0;
22884edd8523SJack F Vogel
22897d9119bdSJack F Vogel DEBUGFUNC("e1000_sw_lcd_config_ich8lan");
22904edd8523SJack F Vogel
22916ab6bfe3SJack F Vogel /* Initialize the PHY from the NVM on ICH platforms. This
22924edd8523SJack F Vogel * is needed due to an issue where the NVM configuration is
22934edd8523SJack F Vogel * not properly autoloaded after power transitions.
22944edd8523SJack F Vogel * Therefore, after each PHY reset, we will load the
22954edd8523SJack F Vogel * configuration data out of the NVM manually.
22964edd8523SJack F Vogel */
22977d9119bdSJack F Vogel switch (hw->mac.type) {
22987d9119bdSJack F Vogel case e1000_ich8lan:
22997d9119bdSJack F Vogel if (phy->type != e1000_phy_igp_3)
23007d9119bdSJack F Vogel return ret_val;
23017d9119bdSJack F Vogel
23027d9119bdSJack F Vogel if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_AMT) ||
23037d9119bdSJack F Vogel (hw->device_id == E1000_DEV_ID_ICH8_IGP_C)) {
23044edd8523SJack F Vogel sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
23057d9119bdSJack F Vogel break;
23067d9119bdSJack F Vogel }
2307e05d9788SKevin Bowling /* FALLTHROUGH */
23087d9119bdSJack F Vogel case e1000_pchlan:
23097d9119bdSJack F Vogel case e1000_pch2lan:
23106ab6bfe3SJack F Vogel case e1000_pch_lpt:
2311c80429ceSEric Joyner case e1000_pch_spt:
23126fe4c0a0SSean Bruno case e1000_pch_cnp:
231359690eabSKevin Bowling case e1000_pch_tgp:
231459690eabSKevin Bowling case e1000_pch_adp:
231559690eabSKevin Bowling case e1000_pch_mtp:
2316*905ae588SKevin Bowling case e1000_pch_ptp:
23177d9119bdSJack F Vogel sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
23187d9119bdSJack F Vogel break;
23197d9119bdSJack F Vogel default:
23207d9119bdSJack F Vogel return ret_val;
23217d9119bdSJack F Vogel }
23227d9119bdSJack F Vogel
23237d9119bdSJack F Vogel ret_val = hw->phy.ops.acquire(hw);
23247d9119bdSJack F Vogel if (ret_val)
23257d9119bdSJack F Vogel return ret_val;
23264edd8523SJack F Vogel
23274edd8523SJack F Vogel data = E1000_READ_REG(hw, E1000_FEXTNVM);
23284edd8523SJack F Vogel if (!(data & sw_cfg_mask))
23296ab6bfe3SJack F Vogel goto release;
23304edd8523SJack F Vogel
23316ab6bfe3SJack F Vogel /* Make sure HW does not configure LCD from PHY
23324edd8523SJack F Vogel * extended configuration before SW configuration
23334edd8523SJack F Vogel */
23344edd8523SJack F Vogel data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
23356ab6bfe3SJack F Vogel if ((hw->mac.type < e1000_pch2lan) &&
23366ab6bfe3SJack F Vogel (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE))
23376ab6bfe3SJack F Vogel goto release;
23384edd8523SJack F Vogel
23394edd8523SJack F Vogel cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE);
23404edd8523SJack F Vogel cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
23414edd8523SJack F Vogel cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
23424edd8523SJack F Vogel if (!cnf_size)
23436ab6bfe3SJack F Vogel goto release;
23444edd8523SJack F Vogel
23454edd8523SJack F Vogel cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
23464edd8523SJack F Vogel cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
23474edd8523SJack F Vogel
23486ab6bfe3SJack F Vogel if (((hw->mac.type == e1000_pchlan) &&
23496ab6bfe3SJack F Vogel !(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)) ||
23506ab6bfe3SJack F Vogel (hw->mac.type > e1000_pchlan)) {
23516ab6bfe3SJack F Vogel /* HW configures the SMBus address and LEDs when the
23524edd8523SJack F Vogel * OEM and LCD Write Enable bits are set in the NVM.
23534edd8523SJack F Vogel * When both NVM bits are cleared, SW will configure
23544edd8523SJack F Vogel * them instead.
23554edd8523SJack F Vogel */
23567d9119bdSJack F Vogel ret_val = e1000_write_smbus_addr(hw);
23574edd8523SJack F Vogel if (ret_val)
23586ab6bfe3SJack F Vogel goto release;
23594edd8523SJack F Vogel
23604edd8523SJack F Vogel data = E1000_READ_REG(hw, E1000_LEDCTL);
2361a69ed8dfSJack F Vogel ret_val = e1000_write_phy_reg_hv_locked(hw, HV_LED_CONFIG,
23624edd8523SJack F Vogel (u16)data);
23634edd8523SJack F Vogel if (ret_val)
23646ab6bfe3SJack F Vogel goto release;
23654edd8523SJack F Vogel }
23664edd8523SJack F Vogel
23674edd8523SJack F Vogel /* Configure LCD from extended configuration region. */
23684edd8523SJack F Vogel
23694edd8523SJack F Vogel /* cnf_base_addr is in DWORD */
23704edd8523SJack F Vogel word_addr = (u16)(cnf_base_addr << 1);
23714edd8523SJack F Vogel
23724edd8523SJack F Vogel for (i = 0; i < cnf_size; i++) {
23734edd8523SJack F Vogel ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2), 1,
23744edd8523SJack F Vogel ®_data);
23754edd8523SJack F Vogel if (ret_val)
23766ab6bfe3SJack F Vogel goto release;
23774edd8523SJack F Vogel
23784edd8523SJack F Vogel ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2 + 1),
23794edd8523SJack F Vogel 1, ®_addr);
23804edd8523SJack F Vogel if (ret_val)
23816ab6bfe3SJack F Vogel goto release;
23824edd8523SJack F Vogel
23834edd8523SJack F Vogel /* Save off the PHY page for future writes. */
23844edd8523SJack F Vogel if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
23854edd8523SJack F Vogel phy_page = reg_data;
23864edd8523SJack F Vogel continue;
23874edd8523SJack F Vogel }
23884edd8523SJack F Vogel
23894edd8523SJack F Vogel reg_addr &= PHY_REG_MASK;
23904edd8523SJack F Vogel reg_addr |= phy_page;
23914edd8523SJack F Vogel
23924edd8523SJack F Vogel ret_val = phy->ops.write_reg_locked(hw, (u32)reg_addr,
23934edd8523SJack F Vogel reg_data);
23944edd8523SJack F Vogel if (ret_val)
23956ab6bfe3SJack F Vogel goto release;
23964edd8523SJack F Vogel }
23974edd8523SJack F Vogel
23986ab6bfe3SJack F Vogel release:
23994edd8523SJack F Vogel hw->phy.ops.release(hw);
24004edd8523SJack F Vogel return ret_val;
24014edd8523SJack F Vogel }
24024edd8523SJack F Vogel
24034edd8523SJack F Vogel /**
24044edd8523SJack F Vogel * e1000_k1_gig_workaround_hv - K1 Si workaround
24054edd8523SJack F Vogel * @hw: pointer to the HW structure
24064edd8523SJack F Vogel * @link: link up bool flag
24074edd8523SJack F Vogel *
24084edd8523SJack F Vogel * If K1 is enabled for 1Gbps, the MAC might stall when transitioning
24094edd8523SJack F Vogel * from a lower speed. This workaround disables K1 whenever link is at 1Gig
24104edd8523SJack F Vogel * If link is down, the function will restore the default K1 setting located
24114edd8523SJack F Vogel * in the NVM.
24124edd8523SJack F Vogel **/
e1000_k1_gig_workaround_hv(struct e1000_hw * hw,bool link)24134edd8523SJack F Vogel static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link)
24144edd8523SJack F Vogel {
24154edd8523SJack F Vogel s32 ret_val = E1000_SUCCESS;
24164edd8523SJack F Vogel u16 status_reg = 0;
24174edd8523SJack F Vogel bool k1_enable = hw->dev_spec.ich8lan.nvm_k1_enabled;
24184edd8523SJack F Vogel
24194edd8523SJack F Vogel DEBUGFUNC("e1000_k1_gig_workaround_hv");
24204edd8523SJack F Vogel
24214edd8523SJack F Vogel if (hw->mac.type != e1000_pchlan)
24226ab6bfe3SJack F Vogel return E1000_SUCCESS;
24234edd8523SJack F Vogel
24244edd8523SJack F Vogel /* Wrap the whole flow with the sw flag */
24254edd8523SJack F Vogel ret_val = hw->phy.ops.acquire(hw);
24264edd8523SJack F Vogel if (ret_val)
24276ab6bfe3SJack F Vogel return ret_val;
24284edd8523SJack F Vogel
24294edd8523SJack F Vogel /* Disable K1 when link is 1Gbps, otherwise use the NVM setting */
24304edd8523SJack F Vogel if (link) {
24314edd8523SJack F Vogel if (hw->phy.type == e1000_phy_82578) {
24324edd8523SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, BM_CS_STATUS,
24334edd8523SJack F Vogel &status_reg);
24344edd8523SJack F Vogel if (ret_val)
24354edd8523SJack F Vogel goto release;
24364edd8523SJack F Vogel
24377609433eSJack F Vogel status_reg &= (BM_CS_STATUS_LINK_UP |
24384edd8523SJack F Vogel BM_CS_STATUS_RESOLVED |
24397609433eSJack F Vogel BM_CS_STATUS_SPEED_MASK);
24404edd8523SJack F Vogel
24414edd8523SJack F Vogel if (status_reg == (BM_CS_STATUS_LINK_UP |
24424edd8523SJack F Vogel BM_CS_STATUS_RESOLVED |
24434edd8523SJack F Vogel BM_CS_STATUS_SPEED_1000))
24441bbdc25fSKevin Bowling k1_enable = false;
24454edd8523SJack F Vogel }
24464edd8523SJack F Vogel
24474edd8523SJack F Vogel if (hw->phy.type == e1000_phy_82577) {
24484edd8523SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, HV_M_STATUS,
24494edd8523SJack F Vogel &status_reg);
24504edd8523SJack F Vogel if (ret_val)
24514edd8523SJack F Vogel goto release;
24524edd8523SJack F Vogel
24537609433eSJack F Vogel status_reg &= (HV_M_STATUS_LINK_UP |
24544edd8523SJack F Vogel HV_M_STATUS_AUTONEG_COMPLETE |
24557609433eSJack F Vogel HV_M_STATUS_SPEED_MASK);
24564edd8523SJack F Vogel
24574edd8523SJack F Vogel if (status_reg == (HV_M_STATUS_LINK_UP |
24584edd8523SJack F Vogel HV_M_STATUS_AUTONEG_COMPLETE |
24594edd8523SJack F Vogel HV_M_STATUS_SPEED_1000))
24601bbdc25fSKevin Bowling k1_enable = false;
24614edd8523SJack F Vogel }
24624edd8523SJack F Vogel
24634edd8523SJack F Vogel /* Link stall fix for link up */
24644edd8523SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
24654edd8523SJack F Vogel 0x0100);
24664edd8523SJack F Vogel if (ret_val)
24674edd8523SJack F Vogel goto release;
24684edd8523SJack F Vogel
24694edd8523SJack F Vogel } else {
24704edd8523SJack F Vogel /* Link stall fix for link down */
24714edd8523SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
24724edd8523SJack F Vogel 0x4100);
24734edd8523SJack F Vogel if (ret_val)
24744edd8523SJack F Vogel goto release;
24754edd8523SJack F Vogel }
24764edd8523SJack F Vogel
24774edd8523SJack F Vogel ret_val = e1000_configure_k1_ich8lan(hw, k1_enable);
24784edd8523SJack F Vogel
24794edd8523SJack F Vogel release:
24804edd8523SJack F Vogel hw->phy.ops.release(hw);
24816ab6bfe3SJack F Vogel
24824edd8523SJack F Vogel return ret_val;
24834edd8523SJack F Vogel }
24844edd8523SJack F Vogel
24854edd8523SJack F Vogel /**
24864edd8523SJack F Vogel * e1000_configure_k1_ich8lan - Configure K1 power state
24874edd8523SJack F Vogel * @hw: pointer to the HW structure
24886c59e186SGuinan Sun * @k1_enable: K1 state to configure
24894edd8523SJack F Vogel *
24904edd8523SJack F Vogel * Configure the K1 power state based on the provided parameter.
24914edd8523SJack F Vogel * Assumes semaphore already acquired.
24924edd8523SJack F Vogel *
24934edd8523SJack F Vogel * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
24944edd8523SJack F Vogel **/
e1000_configure_k1_ich8lan(struct e1000_hw * hw,bool k1_enable)24954edd8523SJack F Vogel s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable)
24964edd8523SJack F Vogel {
24976ab6bfe3SJack F Vogel s32 ret_val;
24984edd8523SJack F Vogel u32 ctrl_reg = 0;
24994edd8523SJack F Vogel u32 ctrl_ext = 0;
25004edd8523SJack F Vogel u32 reg = 0;
25014edd8523SJack F Vogel u16 kmrn_reg = 0;
25024edd8523SJack F Vogel
25037d9119bdSJack F Vogel DEBUGFUNC("e1000_configure_k1_ich8lan");
25047d9119bdSJack F Vogel
25054dab5c37SJack F Vogel ret_val = e1000_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG,
25064edd8523SJack F Vogel &kmrn_reg);
25074edd8523SJack F Vogel if (ret_val)
25086ab6bfe3SJack F Vogel return ret_val;
25094edd8523SJack F Vogel
25104edd8523SJack F Vogel if (k1_enable)
25114edd8523SJack F Vogel kmrn_reg |= E1000_KMRNCTRLSTA_K1_ENABLE;
25124edd8523SJack F Vogel else
25134edd8523SJack F Vogel kmrn_reg &= ~E1000_KMRNCTRLSTA_K1_ENABLE;
25144edd8523SJack F Vogel
25154dab5c37SJack F Vogel ret_val = e1000_write_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG,
25164edd8523SJack F Vogel kmrn_reg);
25174edd8523SJack F Vogel if (ret_val)
25186ab6bfe3SJack F Vogel return ret_val;
25194edd8523SJack F Vogel
25204edd8523SJack F Vogel usec_delay(20);
25214edd8523SJack F Vogel ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
25224edd8523SJack F Vogel ctrl_reg = E1000_READ_REG(hw, E1000_CTRL);
25234edd8523SJack F Vogel
25244edd8523SJack F Vogel reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
25254edd8523SJack F Vogel reg |= E1000_CTRL_FRCSPD;
25264edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, reg);
25274edd8523SJack F Vogel
25284edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_SPD_BYPS);
25294dab5c37SJack F Vogel E1000_WRITE_FLUSH(hw);
25304edd8523SJack F Vogel usec_delay(20);
25314edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg);
25324edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
25334dab5c37SJack F Vogel E1000_WRITE_FLUSH(hw);
25344edd8523SJack F Vogel usec_delay(20);
25354edd8523SJack F Vogel
25366ab6bfe3SJack F Vogel return E1000_SUCCESS;
25374edd8523SJack F Vogel }
25384edd8523SJack F Vogel
25394edd8523SJack F Vogel /**
25404edd8523SJack F Vogel * e1000_oem_bits_config_ich8lan - SW-based LCD Configuration
25414edd8523SJack F Vogel * @hw: pointer to the HW structure
25424edd8523SJack F Vogel * @d0_state: boolean if entering d0 or d3 device state
25434edd8523SJack F Vogel *
25444edd8523SJack F Vogel * SW will configure Gbe Disable and LPLU based on the NVM. The four bits are
25454edd8523SJack F Vogel * collectively called OEM bits. The OEM Write Enable bit and SW Config bit
25464edd8523SJack F Vogel * in NVM determines whether HW should configure LPLU and Gbe Disable.
25474edd8523SJack F Vogel **/
e1000_oem_bits_config_ich8lan(struct e1000_hw * hw,bool d0_state)25484dab5c37SJack F Vogel static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state)
25494edd8523SJack F Vogel {
25504edd8523SJack F Vogel s32 ret_val = 0;
25514edd8523SJack F Vogel u32 mac_reg;
25524edd8523SJack F Vogel u16 oem_reg;
25534edd8523SJack F Vogel
25547d9119bdSJack F Vogel DEBUGFUNC("e1000_oem_bits_config_ich8lan");
25557d9119bdSJack F Vogel
25566ab6bfe3SJack F Vogel if (hw->mac.type < e1000_pchlan)
25574edd8523SJack F Vogel return ret_val;
25584edd8523SJack F Vogel
25594edd8523SJack F Vogel ret_val = hw->phy.ops.acquire(hw);
25604edd8523SJack F Vogel if (ret_val)
25614edd8523SJack F Vogel return ret_val;
25624edd8523SJack F Vogel
25636ab6bfe3SJack F Vogel if (hw->mac.type == e1000_pchlan) {
25644edd8523SJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
25654edd8523SJack F Vogel if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
25666ab6bfe3SJack F Vogel goto release;
25677d9119bdSJack F Vogel }
25684edd8523SJack F Vogel
25694edd8523SJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM);
25704edd8523SJack F Vogel if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M))
25716ab6bfe3SJack F Vogel goto release;
25724edd8523SJack F Vogel
25734edd8523SJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_PHY_CTRL);
25744edd8523SJack F Vogel
25754edd8523SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, HV_OEM_BITS, &oem_reg);
25764edd8523SJack F Vogel if (ret_val)
25776ab6bfe3SJack F Vogel goto release;
25784edd8523SJack F Vogel
25794edd8523SJack F Vogel oem_reg &= ~(HV_OEM_BITS_GBE_DIS | HV_OEM_BITS_LPLU);
25804edd8523SJack F Vogel
25814edd8523SJack F Vogel if (d0_state) {
25824edd8523SJack F Vogel if (mac_reg & E1000_PHY_CTRL_GBE_DISABLE)
25834edd8523SJack F Vogel oem_reg |= HV_OEM_BITS_GBE_DIS;
25844edd8523SJack F Vogel
25854edd8523SJack F Vogel if (mac_reg & E1000_PHY_CTRL_D0A_LPLU)
25864edd8523SJack F Vogel oem_reg |= HV_OEM_BITS_LPLU;
25874dab5c37SJack F Vogel } else {
25884dab5c37SJack F Vogel if (mac_reg & (E1000_PHY_CTRL_GBE_DISABLE |
25894dab5c37SJack F Vogel E1000_PHY_CTRL_NOND0A_GBE_DISABLE))
25904dab5c37SJack F Vogel oem_reg |= HV_OEM_BITS_GBE_DIS;
25914dab5c37SJack F Vogel
25924dab5c37SJack F Vogel if (mac_reg & (E1000_PHY_CTRL_D0A_LPLU |
25934dab5c37SJack F Vogel E1000_PHY_CTRL_NOND0A_LPLU))
25944dab5c37SJack F Vogel oem_reg |= HV_OEM_BITS_LPLU;
25954dab5c37SJack F Vogel }
25964dab5c37SJack F Vogel
25976ab6bfe3SJack F Vogel /* Set Restart auto-neg to activate the bits */
25986ab6bfe3SJack F Vogel if ((d0_state || (hw->mac.type != e1000_pchlan)) &&
25996ab6bfe3SJack F Vogel !hw->phy.ops.check_reset_block(hw))
26006ab6bfe3SJack F Vogel oem_reg |= HV_OEM_BITS_RESTART_AN;
26016ab6bfe3SJack F Vogel
26024edd8523SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, HV_OEM_BITS, oem_reg);
26034edd8523SJack F Vogel
26046ab6bfe3SJack F Vogel release:
26054edd8523SJack F Vogel hw->phy.ops.release(hw);
26064edd8523SJack F Vogel
26074edd8523SJack F Vogel return ret_val;
26084edd8523SJack F Vogel }
26094edd8523SJack F Vogel
26104edd8523SJack F Vogel
26114edd8523SJack F Vogel /**
2612a69ed8dfSJack F Vogel * e1000_set_mdio_slow_mode_hv - Set slow MDIO access mode
2613a69ed8dfSJack F Vogel * @hw: pointer to the HW structure
2614a69ed8dfSJack F Vogel **/
e1000_set_mdio_slow_mode_hv(struct e1000_hw * hw)2615a69ed8dfSJack F Vogel static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw)
2616a69ed8dfSJack F Vogel {
2617a69ed8dfSJack F Vogel s32 ret_val;
2618a69ed8dfSJack F Vogel u16 data;
2619a69ed8dfSJack F Vogel
26207d9119bdSJack F Vogel DEBUGFUNC("e1000_set_mdio_slow_mode_hv");
26217d9119bdSJack F Vogel
2622a69ed8dfSJack F Vogel ret_val = hw->phy.ops.read_reg(hw, HV_KMRN_MODE_CTRL, &data);
2623a69ed8dfSJack F Vogel if (ret_val)
2624a69ed8dfSJack F Vogel return ret_val;
2625a69ed8dfSJack F Vogel
2626a69ed8dfSJack F Vogel data |= HV_KMRN_MDIO_SLOW;
2627a69ed8dfSJack F Vogel
2628a69ed8dfSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, HV_KMRN_MODE_CTRL, data);
2629a69ed8dfSJack F Vogel
2630a69ed8dfSJack F Vogel return ret_val;
2631a69ed8dfSJack F Vogel }
2632a69ed8dfSJack F Vogel
2633a69ed8dfSJack F Vogel /**
26349d81738fSJack F Vogel * e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be
26359d81738fSJack F Vogel * done after every PHY reset.
26366c59e186SGuinan Sun * @hw: pointer to the HW structure
26379d81738fSJack F Vogel **/
e1000_hv_phy_workarounds_ich8lan(struct e1000_hw * hw)26389d81738fSJack F Vogel static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw)
26399d81738fSJack F Vogel {
26409d81738fSJack F Vogel s32 ret_val = E1000_SUCCESS;
2641a69ed8dfSJack F Vogel u16 phy_data;
26429d81738fSJack F Vogel
26437d9119bdSJack F Vogel DEBUGFUNC("e1000_hv_phy_workarounds_ich8lan");
26447d9119bdSJack F Vogel
26459d81738fSJack F Vogel if (hw->mac.type != e1000_pchlan)
26466ab6bfe3SJack F Vogel return E1000_SUCCESS;
26479d81738fSJack F Vogel
2648a69ed8dfSJack F Vogel /* Set MDIO slow mode before any other MDIO access */
2649a69ed8dfSJack F Vogel if (hw->phy.type == e1000_phy_82577) {
2650a69ed8dfSJack F Vogel ret_val = e1000_set_mdio_slow_mode_hv(hw);
2651a69ed8dfSJack F Vogel if (ret_val)
26526ab6bfe3SJack F Vogel return ret_val;
2653a69ed8dfSJack F Vogel }
2654a69ed8dfSJack F Vogel
26559d81738fSJack F Vogel if (((hw->phy.type == e1000_phy_82577) &&
26569d81738fSJack F Vogel ((hw->phy.revision == 1) || (hw->phy.revision == 2))) ||
26579d81738fSJack F Vogel ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) {
26589d81738fSJack F Vogel /* Disable generation of early preamble */
26599d81738fSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431);
26609d81738fSJack F Vogel if (ret_val)
26616ab6bfe3SJack F Vogel return ret_val;
26629d81738fSJack F Vogel
26639d81738fSJack F Vogel /* Preamble tuning for SSC */
26644dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, HV_KMRN_FIFO_CTRLSTA,
26654dab5c37SJack F Vogel 0xA204);
26669d81738fSJack F Vogel if (ret_val)
26676ab6bfe3SJack F Vogel return ret_val;
26689d81738fSJack F Vogel }
26699d81738fSJack F Vogel
26709d81738fSJack F Vogel if (hw->phy.type == e1000_phy_82578) {
26716ab6bfe3SJack F Vogel /* Return registers to default by doing a soft reset then
26729d81738fSJack F Vogel * writing 0x3140 to the control register.
26739d81738fSJack F Vogel */
26749d81738fSJack F Vogel if (hw->phy.revision < 2) {
26759d81738fSJack F Vogel e1000_phy_sw_reset_generic(hw);
26769d81738fSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL,
26779d81738fSJack F Vogel 0x3140);
26786fe4c0a0SSean Bruno if (ret_val)
26796fe4c0a0SSean Bruno return ret_val;
26809d81738fSJack F Vogel }
26819d81738fSJack F Vogel }
26829d81738fSJack F Vogel
26839d81738fSJack F Vogel /* Select page 0 */
26849d81738fSJack F Vogel ret_val = hw->phy.ops.acquire(hw);
26859d81738fSJack F Vogel if (ret_val)
26866ab6bfe3SJack F Vogel return ret_val;
26874edd8523SJack F Vogel
26889d81738fSJack F Vogel hw->phy.addr = 1;
26894edd8523SJack F Vogel ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0);
2690a69ed8dfSJack F Vogel hw->phy.ops.release(hw);
26914edd8523SJack F Vogel if (ret_val)
26926ab6bfe3SJack F Vogel return ret_val;
26939d81738fSJack F Vogel
26946ab6bfe3SJack F Vogel /* Configure the K1 Si workaround during phy reset assuming there is
26954edd8523SJack F Vogel * link so that it disables K1 if link is in 1Gbps.
26964edd8523SJack F Vogel */
26971bbdc25fSKevin Bowling ret_val = e1000_k1_gig_workaround_hv(hw, true);
2698a69ed8dfSJack F Vogel if (ret_val)
26996ab6bfe3SJack F Vogel return ret_val;
27004edd8523SJack F Vogel
2701a69ed8dfSJack F Vogel /* Workaround for link disconnects on a busy hub in half duplex */
2702a69ed8dfSJack F Vogel ret_val = hw->phy.ops.acquire(hw);
2703a69ed8dfSJack F Vogel if (ret_val)
27046ab6bfe3SJack F Vogel return ret_val;
27054dab5c37SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, BM_PORT_GEN_CFG, &phy_data);
2706a69ed8dfSJack F Vogel if (ret_val)
2707a69ed8dfSJack F Vogel goto release;
27084dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, BM_PORT_GEN_CFG,
2709a69ed8dfSJack F Vogel phy_data & 0x00FF);
27106ab6bfe3SJack F Vogel if (ret_val)
27116ab6bfe3SJack F Vogel goto release;
27126ab6bfe3SJack F Vogel
27136ab6bfe3SJack F Vogel /* set MSE higher to enable link to stay up when noise is high */
27146ab6bfe3SJack F Vogel ret_val = e1000_write_emi_reg_locked(hw, I82577_MSE_THRESHOLD, 0x0034);
2715a69ed8dfSJack F Vogel release:
2716a69ed8dfSJack F Vogel hw->phy.ops.release(hw);
27176ab6bfe3SJack F Vogel
27189d81738fSJack F Vogel return ret_val;
27199d81738fSJack F Vogel }
27209d81738fSJack F Vogel
27219d81738fSJack F Vogel /**
27227d9119bdSJack F Vogel * e1000_copy_rx_addrs_to_phy_ich8lan - Copy Rx addresses from MAC to PHY
27237d9119bdSJack F Vogel * @hw: pointer to the HW structure
27247d9119bdSJack F Vogel **/
e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw * hw)27257d9119bdSJack F Vogel void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw)
27267d9119bdSJack F Vogel {
27277d9119bdSJack F Vogel u32 mac_reg;
27284dab5c37SJack F Vogel u16 i, phy_reg = 0;
27294dab5c37SJack F Vogel s32 ret_val;
27307d9119bdSJack F Vogel
27317d9119bdSJack F Vogel DEBUGFUNC("e1000_copy_rx_addrs_to_phy_ich8lan");
27327d9119bdSJack F Vogel
27334dab5c37SJack F Vogel ret_val = hw->phy.ops.acquire(hw);
27344dab5c37SJack F Vogel if (ret_val)
27354dab5c37SJack F Vogel return;
27364dab5c37SJack F Vogel ret_val = e1000_enable_phy_wakeup_reg_access_bm(hw, &phy_reg);
27374dab5c37SJack F Vogel if (ret_val)
27384dab5c37SJack F Vogel goto release;
27394dab5c37SJack F Vogel
27407609433eSJack F Vogel /* Copy both RAL/H (rar_entry_count) and SHRAL/H to PHY */
27417609433eSJack F Vogel for (i = 0; i < (hw->mac.rar_entry_count); i++) {
27427d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_RAL(i));
27434dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, BM_RAR_L(i),
27444dab5c37SJack F Vogel (u16)(mac_reg & 0xFFFF));
27454dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, BM_RAR_M(i),
27464dab5c37SJack F Vogel (u16)((mac_reg >> 16) & 0xFFFF));
27474dab5c37SJack F Vogel
27487d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_RAH(i));
27494dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, BM_RAR_H(i),
27504dab5c37SJack F Vogel (u16)(mac_reg & 0xFFFF));
27514dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, BM_RAR_CTRL(i),
27524dab5c37SJack F Vogel (u16)((mac_reg & E1000_RAH_AV)
27534dab5c37SJack F Vogel >> 16));
27547d9119bdSJack F Vogel }
27554dab5c37SJack F Vogel
27564dab5c37SJack F Vogel e1000_disable_phy_wakeup_reg_access_bm(hw, &phy_reg);
27574dab5c37SJack F Vogel
27584dab5c37SJack F Vogel release:
27594dab5c37SJack F Vogel hw->phy.ops.release(hw);
27607d9119bdSJack F Vogel }
27617d9119bdSJack F Vogel
e1000_calc_rx_da_crc(u8 mac[])27627d9119bdSJack F Vogel static u32 e1000_calc_rx_da_crc(u8 mac[])
27637d9119bdSJack F Vogel {
27647d9119bdSJack F Vogel u32 poly = 0xEDB88320; /* Polynomial for 802.3 CRC calculation */
27657d9119bdSJack F Vogel u32 i, j, mask, crc;
27667d9119bdSJack F Vogel
27677d9119bdSJack F Vogel DEBUGFUNC("e1000_calc_rx_da_crc");
27687d9119bdSJack F Vogel
27697d9119bdSJack F Vogel crc = 0xffffffff;
27707d9119bdSJack F Vogel for (i = 0; i < 6; i++) {
27717d9119bdSJack F Vogel crc = crc ^ mac[i];
27727d9119bdSJack F Vogel for (j = 8; j > 0; j--) {
27737d9119bdSJack F Vogel mask = (crc & 1) * (-1);
27747d9119bdSJack F Vogel crc = (crc >> 1) ^ (poly & mask);
27757d9119bdSJack F Vogel }
27767d9119bdSJack F Vogel }
27777d9119bdSJack F Vogel return ~crc;
27787d9119bdSJack F Vogel }
27797d9119bdSJack F Vogel
27807d9119bdSJack F Vogel /**
27817d9119bdSJack F Vogel * e1000_lv_jumbo_workaround_ich8lan - required for jumbo frame operation
27827d9119bdSJack F Vogel * with 82579 PHY
27837d9119bdSJack F Vogel * @hw: pointer to the HW structure
27847d9119bdSJack F Vogel * @enable: flag to enable/disable workaround when enabling/disabling jumbos
27857d9119bdSJack F Vogel **/
e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw * hw,bool enable)27867d9119bdSJack F Vogel s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable)
27877d9119bdSJack F Vogel {
27887d9119bdSJack F Vogel s32 ret_val = E1000_SUCCESS;
27897d9119bdSJack F Vogel u16 phy_reg, data;
27907d9119bdSJack F Vogel u32 mac_reg;
27917d9119bdSJack F Vogel u16 i;
27927d9119bdSJack F Vogel
27937d9119bdSJack F Vogel DEBUGFUNC("e1000_lv_jumbo_workaround_ich8lan");
27947d9119bdSJack F Vogel
27956ab6bfe3SJack F Vogel if (hw->mac.type < e1000_pch2lan)
27966ab6bfe3SJack F Vogel return E1000_SUCCESS;
27977d9119bdSJack F Vogel
27987d9119bdSJack F Vogel /* disable Rx path while enabling/disabling workaround */
27997d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(769, 20), &phy_reg);
28004dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 20),
28014dab5c37SJack F Vogel phy_reg | (1 << 14));
28027d9119bdSJack F Vogel if (ret_val)
28036ab6bfe3SJack F Vogel return ret_val;
28047d9119bdSJack F Vogel
28057d9119bdSJack F Vogel if (enable) {
28067609433eSJack F Vogel /* Write Rx addresses (rar_entry_count for RAL/H, and
28077d9119bdSJack F Vogel * SHRAL/H) and initial CRC values to the MAC
28087d9119bdSJack F Vogel */
28097609433eSJack F Vogel for (i = 0; i < hw->mac.rar_entry_count; i++) {
2810e81998f4SEric Joyner u8 mac_addr[ETHER_ADDR_LEN] = {0};
28117d9119bdSJack F Vogel u32 addr_high, addr_low;
28127d9119bdSJack F Vogel
28137d9119bdSJack F Vogel addr_high = E1000_READ_REG(hw, E1000_RAH(i));
28147d9119bdSJack F Vogel if (!(addr_high & E1000_RAH_AV))
28157d9119bdSJack F Vogel continue;
28167d9119bdSJack F Vogel addr_low = E1000_READ_REG(hw, E1000_RAL(i));
28177d9119bdSJack F Vogel mac_addr[0] = (addr_low & 0xFF);
28187d9119bdSJack F Vogel mac_addr[1] = ((addr_low >> 8) & 0xFF);
28197d9119bdSJack F Vogel mac_addr[2] = ((addr_low >> 16) & 0xFF);
28207d9119bdSJack F Vogel mac_addr[3] = ((addr_low >> 24) & 0xFF);
28217d9119bdSJack F Vogel mac_addr[4] = (addr_high & 0xFF);
28227d9119bdSJack F Vogel mac_addr[5] = ((addr_high >> 8) & 0xFF);
28237d9119bdSJack F Vogel
28247d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_PCH_RAICC(i),
28257d9119bdSJack F Vogel e1000_calc_rx_da_crc(mac_addr));
28267d9119bdSJack F Vogel }
28277d9119bdSJack F Vogel
28287d9119bdSJack F Vogel /* Write Rx addresses to the PHY */
28297d9119bdSJack F Vogel e1000_copy_rx_addrs_to_phy_ich8lan(hw);
28307d9119bdSJack F Vogel
28317d9119bdSJack F Vogel /* Enable jumbo frame workaround in the MAC */
28327d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG);
28337d9119bdSJack F Vogel mac_reg &= ~(1 << 14);
28347d9119bdSJack F Vogel mac_reg |= (7 << 15);
28357d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg);
28367d9119bdSJack F Vogel
28377d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_RCTL);
28387d9119bdSJack F Vogel mac_reg |= E1000_RCTL_SECRC;
28397d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_RCTL, mac_reg);
28407d9119bdSJack F Vogel
28417d9119bdSJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw,
28427d9119bdSJack F Vogel E1000_KMRNCTRLSTA_CTRL_OFFSET,
28437d9119bdSJack F Vogel &data);
28447d9119bdSJack F Vogel if (ret_val)
28456ab6bfe3SJack F Vogel return ret_val;
28467d9119bdSJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw,
28477d9119bdSJack F Vogel E1000_KMRNCTRLSTA_CTRL_OFFSET,
28487d9119bdSJack F Vogel data | (1 << 0));
28497d9119bdSJack F Vogel if (ret_val)
28506ab6bfe3SJack F Vogel return ret_val;
28517d9119bdSJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw,
28527d9119bdSJack F Vogel E1000_KMRNCTRLSTA_HD_CTRL,
28537d9119bdSJack F Vogel &data);
28547d9119bdSJack F Vogel if (ret_val)
28556ab6bfe3SJack F Vogel return ret_val;
28567d9119bdSJack F Vogel data &= ~(0xF << 8);
28577d9119bdSJack F Vogel data |= (0xB << 8);
28587d9119bdSJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw,
28597d9119bdSJack F Vogel E1000_KMRNCTRLSTA_HD_CTRL,
28607d9119bdSJack F Vogel data);
28617d9119bdSJack F Vogel if (ret_val)
28626ab6bfe3SJack F Vogel return ret_val;
28637d9119bdSJack F Vogel
28647d9119bdSJack F Vogel /* Enable jumbo frame workaround in the PHY */
28657d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data);
28667d9119bdSJack F Vogel data &= ~(0x7F << 5);
28677d9119bdSJack F Vogel data |= (0x37 << 5);
28687d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data);
28697d9119bdSJack F Vogel if (ret_val)
28706ab6bfe3SJack F Vogel return ret_val;
28717d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data);
28727d9119bdSJack F Vogel data &= ~(1 << 13);
28737d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data);
28747d9119bdSJack F Vogel if (ret_val)
28756ab6bfe3SJack F Vogel return ret_val;
28767d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data);
28777d9119bdSJack F Vogel data &= ~(0x3FF << 2);
28788cc64f1eSJack F Vogel data |= (E1000_TX_PTR_GAP << 2);
28797d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data);
28807d9119bdSJack F Vogel if (ret_val)
28816ab6bfe3SJack F Vogel return ret_val;
28824dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0xF100);
28837d9119bdSJack F Vogel if (ret_val)
28846ab6bfe3SJack F Vogel return ret_val;
28857d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data);
28864dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data |
28874dab5c37SJack F Vogel (1 << 10));
28887d9119bdSJack F Vogel if (ret_val)
28896ab6bfe3SJack F Vogel return ret_val;
28907d9119bdSJack F Vogel } else {
28917d9119bdSJack F Vogel /* Write MAC register values back to h/w defaults */
28927d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG);
28937d9119bdSJack F Vogel mac_reg &= ~(0xF << 14);
28947d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg);
28957d9119bdSJack F Vogel
28967d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_RCTL);
28977d9119bdSJack F Vogel mac_reg &= ~E1000_RCTL_SECRC;
28987d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_RCTL, mac_reg);
28997d9119bdSJack F Vogel
29007d9119bdSJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw,
29017d9119bdSJack F Vogel E1000_KMRNCTRLSTA_CTRL_OFFSET,
29027d9119bdSJack F Vogel &data);
29037d9119bdSJack F Vogel if (ret_val)
29046ab6bfe3SJack F Vogel return ret_val;
29057d9119bdSJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw,
29067d9119bdSJack F Vogel E1000_KMRNCTRLSTA_CTRL_OFFSET,
29077d9119bdSJack F Vogel data & ~(1 << 0));
29087d9119bdSJack F Vogel if (ret_val)
29096ab6bfe3SJack F Vogel return ret_val;
29107d9119bdSJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw,
29117d9119bdSJack F Vogel E1000_KMRNCTRLSTA_HD_CTRL,
29127d9119bdSJack F Vogel &data);
29137d9119bdSJack F Vogel if (ret_val)
29146ab6bfe3SJack F Vogel return ret_val;
29157d9119bdSJack F Vogel data &= ~(0xF << 8);
29167d9119bdSJack F Vogel data |= (0xB << 8);
29177d9119bdSJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw,
29187d9119bdSJack F Vogel E1000_KMRNCTRLSTA_HD_CTRL,
29197d9119bdSJack F Vogel data);
29207d9119bdSJack F Vogel if (ret_val)
29216ab6bfe3SJack F Vogel return ret_val;
29227d9119bdSJack F Vogel
29237d9119bdSJack F Vogel /* Write PHY register values back to h/w defaults */
29247d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data);
29257d9119bdSJack F Vogel data &= ~(0x7F << 5);
29267d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data);
29277d9119bdSJack F Vogel if (ret_val)
29286ab6bfe3SJack F Vogel return ret_val;
29297d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data);
29307d9119bdSJack F Vogel data |= (1 << 13);
29317d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data);
29327d9119bdSJack F Vogel if (ret_val)
29336ab6bfe3SJack F Vogel return ret_val;
29347d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data);
29357d9119bdSJack F Vogel data &= ~(0x3FF << 2);
29367d9119bdSJack F Vogel data |= (0x8 << 2);
29377d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data);
29387d9119bdSJack F Vogel if (ret_val)
29396ab6bfe3SJack F Vogel return ret_val;
29407d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0x7E00);
29417d9119bdSJack F Vogel if (ret_val)
29426ab6bfe3SJack F Vogel return ret_val;
29437d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data);
29444dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data &
29454dab5c37SJack F Vogel ~(1 << 10));
29467d9119bdSJack F Vogel if (ret_val)
29476ab6bfe3SJack F Vogel return ret_val;
29487d9119bdSJack F Vogel }
29497d9119bdSJack F Vogel
29507d9119bdSJack F Vogel /* re-enable Rx path after enabling/disabling workaround */
29516ab6bfe3SJack F Vogel return hw->phy.ops.write_reg(hw, PHY_REG(769, 20), phy_reg &
29524dab5c37SJack F Vogel ~(1 << 14));
29537d9119bdSJack F Vogel }
29547d9119bdSJack F Vogel
29557d9119bdSJack F Vogel /**
29567d9119bdSJack F Vogel * e1000_lv_phy_workarounds_ich8lan - A series of Phy workarounds to be
29577d9119bdSJack F Vogel * done after every PHY reset.
29586c59e186SGuinan Sun * @hw: pointer to the HW structure
29597d9119bdSJack F Vogel **/
e1000_lv_phy_workarounds_ich8lan(struct e1000_hw * hw)29607d9119bdSJack F Vogel static s32 e1000_lv_phy_workarounds_ich8lan(struct e1000_hw *hw)
29617d9119bdSJack F Vogel {
29627d9119bdSJack F Vogel s32 ret_val = E1000_SUCCESS;
29637d9119bdSJack F Vogel
29647d9119bdSJack F Vogel DEBUGFUNC("e1000_lv_phy_workarounds_ich8lan");
29657d9119bdSJack F Vogel
29667d9119bdSJack F Vogel if (hw->mac.type != e1000_pch2lan)
29676ab6bfe3SJack F Vogel return E1000_SUCCESS;
29687d9119bdSJack F Vogel
29697d9119bdSJack F Vogel /* Set MDIO slow mode before any other MDIO access */
29707d9119bdSJack F Vogel ret_val = e1000_set_mdio_slow_mode_hv(hw);
29716ab6bfe3SJack F Vogel if (ret_val)
29726ab6bfe3SJack F Vogel return ret_val;
29737d9119bdSJack F Vogel
29744dab5c37SJack F Vogel ret_val = hw->phy.ops.acquire(hw);
29754dab5c37SJack F Vogel if (ret_val)
29766ab6bfe3SJack F Vogel return ret_val;
29774dab5c37SJack F Vogel /* set MSE higher to enable link to stay up when noise is high */
29786ab6bfe3SJack F Vogel ret_val = e1000_write_emi_reg_locked(hw, I82579_MSE_THRESHOLD, 0x0034);
29794dab5c37SJack F Vogel if (ret_val)
29804dab5c37SJack F Vogel goto release;
29814dab5c37SJack F Vogel /* drop link after 5 times MSE threshold was reached */
29826ab6bfe3SJack F Vogel ret_val = e1000_write_emi_reg_locked(hw, I82579_MSE_LINK_DOWN, 0x0005);
29834dab5c37SJack F Vogel release:
29844dab5c37SJack F Vogel hw->phy.ops.release(hw);
29854dab5c37SJack F Vogel
29867d9119bdSJack F Vogel return ret_val;
29877d9119bdSJack F Vogel }
29887d9119bdSJack F Vogel
29897d9119bdSJack F Vogel /**
29907d9119bdSJack F Vogel * e1000_k1_gig_workaround_lv - K1 Si workaround
29917d9119bdSJack F Vogel * @hw: pointer to the HW structure
29927d9119bdSJack F Vogel *
29938cc64f1eSJack F Vogel * Workaround to set the K1 beacon duration for 82579 parts in 10Mbps
29948cc64f1eSJack F Vogel * Disable K1 for 1000 and 100 speeds
29957d9119bdSJack F Vogel **/
e1000_k1_workaround_lv(struct e1000_hw * hw)29967d9119bdSJack F Vogel static s32 e1000_k1_workaround_lv(struct e1000_hw *hw)
29977d9119bdSJack F Vogel {
29987d9119bdSJack F Vogel s32 ret_val = E1000_SUCCESS;
29997d9119bdSJack F Vogel u16 status_reg = 0;
30007d9119bdSJack F Vogel
30017d9119bdSJack F Vogel DEBUGFUNC("e1000_k1_workaround_lv");
30027d9119bdSJack F Vogel
30037d9119bdSJack F Vogel if (hw->mac.type != e1000_pch2lan)
30046ab6bfe3SJack F Vogel return E1000_SUCCESS;
30057d9119bdSJack F Vogel
30068cc64f1eSJack F Vogel /* Set K1 beacon duration based on 10Mbs speed */
30077d9119bdSJack F Vogel ret_val = hw->phy.ops.read_reg(hw, HV_M_STATUS, &status_reg);
30087d9119bdSJack F Vogel if (ret_val)
30096ab6bfe3SJack F Vogel return ret_val;
30107d9119bdSJack F Vogel
30117d9119bdSJack F Vogel if ((status_reg & (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE))
30127d9119bdSJack F Vogel == (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE)) {
30138cc64f1eSJack F Vogel if (status_reg &
30148cc64f1eSJack F Vogel (HV_M_STATUS_SPEED_1000 | HV_M_STATUS_SPEED_100)) {
30156ab6bfe3SJack F Vogel u16 pm_phy_reg;
30166ab6bfe3SJack F Vogel
30178cc64f1eSJack F Vogel /* LV 1G/100 Packet drop issue wa */
30186ab6bfe3SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, HV_PM_CTRL,
30196ab6bfe3SJack F Vogel &pm_phy_reg);
30206ab6bfe3SJack F Vogel if (ret_val)
30216ab6bfe3SJack F Vogel return ret_val;
30228cc64f1eSJack F Vogel pm_phy_reg &= ~HV_PM_CTRL_K1_ENABLE;
30236ab6bfe3SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL,
30246ab6bfe3SJack F Vogel pm_phy_reg);
30256ab6bfe3SJack F Vogel if (ret_val)
30266ab6bfe3SJack F Vogel return ret_val;
30274dab5c37SJack F Vogel } else {
30288cc64f1eSJack F Vogel u32 mac_reg;
30298cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM4);
30308cc64f1eSJack F Vogel mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK;
30314dab5c37SJack F Vogel mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_16USEC;
30327d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM4, mac_reg);
30338cc64f1eSJack F Vogel }
30347d9119bdSJack F Vogel }
30357d9119bdSJack F Vogel
30367d9119bdSJack F Vogel return ret_val;
30377d9119bdSJack F Vogel }
30387d9119bdSJack F Vogel
30397d9119bdSJack F Vogel /**
30407d9119bdSJack F Vogel * e1000_gate_hw_phy_config_ich8lan - disable PHY config via hardware
30417d9119bdSJack F Vogel * @hw: pointer to the HW structure
30421bbdc25fSKevin Bowling * @gate: boolean set to true to gate, false to ungate
30437d9119bdSJack F Vogel *
30447d9119bdSJack F Vogel * Gate/ungate the automatic PHY configuration via hardware; perform
30457d9119bdSJack F Vogel * the configuration via software instead.
30467d9119bdSJack F Vogel **/
e1000_gate_hw_phy_config_ich8lan(struct e1000_hw * hw,bool gate)30477d9119bdSJack F Vogel static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate)
30487d9119bdSJack F Vogel {
30497d9119bdSJack F Vogel u32 extcnf_ctrl;
30507d9119bdSJack F Vogel
30517d9119bdSJack F Vogel DEBUGFUNC("e1000_gate_hw_phy_config_ich8lan");
30527d9119bdSJack F Vogel
30536ab6bfe3SJack F Vogel if (hw->mac.type < e1000_pch2lan)
30547d9119bdSJack F Vogel return;
30557d9119bdSJack F Vogel
30567d9119bdSJack F Vogel extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
30577d9119bdSJack F Vogel
30587d9119bdSJack F Vogel if (gate)
30597d9119bdSJack F Vogel extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG;
30607d9119bdSJack F Vogel else
30617d9119bdSJack F Vogel extcnf_ctrl &= ~E1000_EXTCNF_CTRL_GATE_PHY_CFG;
30627d9119bdSJack F Vogel
30637d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
30647d9119bdSJack F Vogel }
30657d9119bdSJack F Vogel
30667d9119bdSJack F Vogel /**
30679d81738fSJack F Vogel * e1000_lan_init_done_ich8lan - Check for PHY config completion
30688cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
30698cfa0ad2SJack F Vogel *
30709d81738fSJack F Vogel * Check the appropriate indication the MAC has finished configuring the
30719d81738fSJack F Vogel * PHY after a software reset.
30728cfa0ad2SJack F Vogel **/
e1000_lan_init_done_ich8lan(struct e1000_hw * hw)30739d81738fSJack F Vogel static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw)
30748cfa0ad2SJack F Vogel {
30759d81738fSJack F Vogel u32 data, loop = E1000_ICH8_LAN_INIT_TIMEOUT;
30768cfa0ad2SJack F Vogel
30779d81738fSJack F Vogel DEBUGFUNC("e1000_lan_init_done_ich8lan");
30788cfa0ad2SJack F Vogel
30799d81738fSJack F Vogel /* Wait for basic configuration completes before proceeding */
30809d81738fSJack F Vogel do {
30819d81738fSJack F Vogel data = E1000_READ_REG(hw, E1000_STATUS);
30829d81738fSJack F Vogel data &= E1000_STATUS_LAN_INIT_DONE;
30839d81738fSJack F Vogel usec_delay(100);
30849d81738fSJack F Vogel } while ((!data) && --loop);
30858cfa0ad2SJack F Vogel
30866ab6bfe3SJack F Vogel /* If basic configuration is incomplete before the above loop
30879d81738fSJack F Vogel * count reaches 0, loading the configuration from NVM will
30889d81738fSJack F Vogel * leave the PHY in a bad state possibly resulting in no link.
30899d81738fSJack F Vogel */
30909d81738fSJack F Vogel if (loop == 0)
30919d81738fSJack F Vogel DEBUGOUT("LAN_INIT_DONE not set, increase timeout\n");
30928cfa0ad2SJack F Vogel
30939d81738fSJack F Vogel /* Clear the Init Done bit for the next init event */
30949d81738fSJack F Vogel data = E1000_READ_REG(hw, E1000_STATUS);
30959d81738fSJack F Vogel data &= ~E1000_STATUS_LAN_INIT_DONE;
30969d81738fSJack F Vogel E1000_WRITE_REG(hw, E1000_STATUS, data);
30978cfa0ad2SJack F Vogel }
30988cfa0ad2SJack F Vogel
30998cfa0ad2SJack F Vogel /**
31007d9119bdSJack F Vogel * e1000_post_phy_reset_ich8lan - Perform steps required after a PHY reset
31017d9119bdSJack F Vogel * @hw: pointer to the HW structure
31027d9119bdSJack F Vogel **/
e1000_post_phy_reset_ich8lan(struct e1000_hw * hw)31037d9119bdSJack F Vogel static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw)
31047d9119bdSJack F Vogel {
31057d9119bdSJack F Vogel s32 ret_val = E1000_SUCCESS;
31067d9119bdSJack F Vogel u16 reg;
31077d9119bdSJack F Vogel
31087d9119bdSJack F Vogel DEBUGFUNC("e1000_post_phy_reset_ich8lan");
31097d9119bdSJack F Vogel
31107d9119bdSJack F Vogel if (hw->phy.ops.check_reset_block(hw))
31116ab6bfe3SJack F Vogel return E1000_SUCCESS;
31127d9119bdSJack F Vogel
31137d9119bdSJack F Vogel /* Allow time for h/w to get to quiescent state after reset */
31147d9119bdSJack F Vogel msec_delay(10);
31157d9119bdSJack F Vogel
31167d9119bdSJack F Vogel /* Perform any necessary post-reset workarounds */
31177d9119bdSJack F Vogel switch (hw->mac.type) {
31187d9119bdSJack F Vogel case e1000_pchlan:
31197d9119bdSJack F Vogel ret_val = e1000_hv_phy_workarounds_ich8lan(hw);
31207d9119bdSJack F Vogel if (ret_val)
31216ab6bfe3SJack F Vogel return ret_val;
31227d9119bdSJack F Vogel break;
31237d9119bdSJack F Vogel case e1000_pch2lan:
31247d9119bdSJack F Vogel ret_val = e1000_lv_phy_workarounds_ich8lan(hw);
31257d9119bdSJack F Vogel if (ret_val)
31266ab6bfe3SJack F Vogel return ret_val;
31277d9119bdSJack F Vogel break;
31287d9119bdSJack F Vogel default:
31297d9119bdSJack F Vogel break;
31307d9119bdSJack F Vogel }
31317d9119bdSJack F Vogel
31324dab5c37SJack F Vogel /* Clear the host wakeup bit after lcd reset */
31334dab5c37SJack F Vogel if (hw->mac.type >= e1000_pchlan) {
31344dab5c37SJack F Vogel hw->phy.ops.read_reg(hw, BM_PORT_GEN_CFG, ®);
31354dab5c37SJack F Vogel reg &= ~BM_WUC_HOST_WU_BIT;
31364dab5c37SJack F Vogel hw->phy.ops.write_reg(hw, BM_PORT_GEN_CFG, reg);
31377d9119bdSJack F Vogel }
31387d9119bdSJack F Vogel
31397d9119bdSJack F Vogel /* Configure the LCD with the extended configuration region in NVM */
31407d9119bdSJack F Vogel ret_val = e1000_sw_lcd_config_ich8lan(hw);
31417d9119bdSJack F Vogel if (ret_val)
31426ab6bfe3SJack F Vogel return ret_val;
31437d9119bdSJack F Vogel
31447d9119bdSJack F Vogel /* Configure the LCD with the OEM bits in NVM */
31451bbdc25fSKevin Bowling ret_val = e1000_oem_bits_config_ich8lan(hw, true);
31467d9119bdSJack F Vogel
3147730d3130SJack F Vogel if (hw->mac.type == e1000_pch2lan) {
31487d9119bdSJack F Vogel /* Ungate automatic PHY configuration on non-managed 82579 */
3149730d3130SJack F Vogel if (!(E1000_READ_REG(hw, E1000_FWSM) &
3150730d3130SJack F Vogel E1000_ICH_FWSM_FW_VALID)) {
31517d9119bdSJack F Vogel msec_delay(10);
31521bbdc25fSKevin Bowling e1000_gate_hw_phy_config_ich8lan(hw, false);
31537d9119bdSJack F Vogel }
31547d9119bdSJack F Vogel
3155730d3130SJack F Vogel /* Set EEE LPI Update Timer to 200usec */
3156730d3130SJack F Vogel ret_val = hw->phy.ops.acquire(hw);
3157730d3130SJack F Vogel if (ret_val)
31586ab6bfe3SJack F Vogel return ret_val;
31596ab6bfe3SJack F Vogel ret_val = e1000_write_emi_reg_locked(hw,
31606ab6bfe3SJack F Vogel I82579_LPI_UPDATE_TIMER,
3161730d3130SJack F Vogel 0x1387);
3162730d3130SJack F Vogel hw->phy.ops.release(hw);
3163730d3130SJack F Vogel }
3164730d3130SJack F Vogel
31657d9119bdSJack F Vogel return ret_val;
31667d9119bdSJack F Vogel }
31677d9119bdSJack F Vogel
31687d9119bdSJack F Vogel /**
31698cfa0ad2SJack F Vogel * e1000_phy_hw_reset_ich8lan - Performs a PHY reset
31708cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
31718cfa0ad2SJack F Vogel *
31728cfa0ad2SJack F Vogel * Resets the PHY
31738cfa0ad2SJack F Vogel * This is a function pointer entry point called by drivers
31748cfa0ad2SJack F Vogel * or other shared routines.
31758cfa0ad2SJack F Vogel **/
e1000_phy_hw_reset_ich8lan(struct e1000_hw * hw)31768cfa0ad2SJack F Vogel static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
31778cfa0ad2SJack F Vogel {
31784edd8523SJack F Vogel s32 ret_val = E1000_SUCCESS;
31798cfa0ad2SJack F Vogel
31808cfa0ad2SJack F Vogel DEBUGFUNC("e1000_phy_hw_reset_ich8lan");
31818cfa0ad2SJack F Vogel
31827d9119bdSJack F Vogel /* Gate automatic PHY configuration by hardware on non-managed 82579 */
31837d9119bdSJack F Vogel if ((hw->mac.type == e1000_pch2lan) &&
31847d9119bdSJack F Vogel !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))
31851bbdc25fSKevin Bowling e1000_gate_hw_phy_config_ich8lan(hw, true);
31867d9119bdSJack F Vogel
31878cfa0ad2SJack F Vogel ret_val = e1000_phy_hw_reset_generic(hw);
31888cfa0ad2SJack F Vogel if (ret_val)
31898cfa0ad2SJack F Vogel return ret_val;
31906ab6bfe3SJack F Vogel
31916ab6bfe3SJack F Vogel return e1000_post_phy_reset_ich8lan(hw);
31928cfa0ad2SJack F Vogel }
31938cfa0ad2SJack F Vogel
31948cfa0ad2SJack F Vogel /**
31954edd8523SJack F Vogel * e1000_set_lplu_state_pchlan - Set Low Power Link Up state
31968cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
31971bbdc25fSKevin Bowling * @active: true to enable LPLU, false to disable
31988cfa0ad2SJack F Vogel *
31994edd8523SJack F Vogel * Sets the LPLU state according to the active flag. For PCH, if OEM write
32004edd8523SJack F Vogel * bit are disabled in the NVM, writing the LPLU bits in the MAC will not set
32014edd8523SJack F Vogel * the phy speed. This function will manually set the LPLU bit and restart
32024edd8523SJack F Vogel * auto-neg as hw would do. D3 and D0 LPLU will call the same function
32034edd8523SJack F Vogel * since it configures the same bit.
32048cfa0ad2SJack F Vogel **/
e1000_set_lplu_state_pchlan(struct e1000_hw * hw,bool active)32054edd8523SJack F Vogel static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active)
32068cfa0ad2SJack F Vogel {
32076ab6bfe3SJack F Vogel s32 ret_val;
32084edd8523SJack F Vogel u16 oem_reg;
32098cfa0ad2SJack F Vogel
32104edd8523SJack F Vogel DEBUGFUNC("e1000_set_lplu_state_pchlan");
32114edd8523SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, HV_OEM_BITS, &oem_reg);
32128cfa0ad2SJack F Vogel if (ret_val)
32136ab6bfe3SJack F Vogel return ret_val;
32148cfa0ad2SJack F Vogel
32154edd8523SJack F Vogel if (active)
32164edd8523SJack F Vogel oem_reg |= HV_OEM_BITS_LPLU;
32174edd8523SJack F Vogel else
32184edd8523SJack F Vogel oem_reg &= ~HV_OEM_BITS_LPLU;
32198cfa0ad2SJack F Vogel
32204dab5c37SJack F Vogel if (!hw->phy.ops.check_reset_block(hw))
32214edd8523SJack F Vogel oem_reg |= HV_OEM_BITS_RESTART_AN;
32224dab5c37SJack F Vogel
32236ab6bfe3SJack F Vogel return hw->phy.ops.write_reg(hw, HV_OEM_BITS, oem_reg);
32248cfa0ad2SJack F Vogel }
32258cfa0ad2SJack F Vogel
32268cfa0ad2SJack F Vogel /**
32278cfa0ad2SJack F Vogel * e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state
32288cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
32291bbdc25fSKevin Bowling * @active: true to enable LPLU, false to disable
32308cfa0ad2SJack F Vogel *
32318cfa0ad2SJack F Vogel * Sets the LPLU D0 state according to the active flag. When
32328cfa0ad2SJack F Vogel * activating LPLU this function also disables smart speed
32338cfa0ad2SJack F Vogel * and vice versa. LPLU will not be activated unless the
32348cfa0ad2SJack F Vogel * device autonegotiation advertisement meets standards of
32358cfa0ad2SJack F Vogel * either 10 or 10/100 or 10/100/1000 at all duplexes.
32368cfa0ad2SJack F Vogel * This is a function pointer entry point only called by
32378cfa0ad2SJack F Vogel * PHY setup routines.
32388cfa0ad2SJack F Vogel **/
e1000_set_d0_lplu_state_ich8lan(struct e1000_hw * hw,bool active)3239daf9197cSJack F Vogel static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
32408cfa0ad2SJack F Vogel {
32418cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy;
32428cfa0ad2SJack F Vogel u32 phy_ctrl;
32438cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS;
32448cfa0ad2SJack F Vogel u16 data;
32458cfa0ad2SJack F Vogel
32468cfa0ad2SJack F Vogel DEBUGFUNC("e1000_set_d0_lplu_state_ich8lan");
32478cfa0ad2SJack F Vogel
32488cfa0ad2SJack F Vogel if (phy->type == e1000_phy_ife)
32496ab6bfe3SJack F Vogel return E1000_SUCCESS;
32508cfa0ad2SJack F Vogel
32518cfa0ad2SJack F Vogel phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
32528cfa0ad2SJack F Vogel
32538cfa0ad2SJack F Vogel if (active) {
32548cfa0ad2SJack F Vogel phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
32558cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
32568cfa0ad2SJack F Vogel
32579d81738fSJack F Vogel if (phy->type != e1000_phy_igp_3)
32586ab6bfe3SJack F Vogel return E1000_SUCCESS;
32599d81738fSJack F Vogel
32606ab6bfe3SJack F Vogel /* Call gig speed drop workaround on LPLU before accessing
32618cfa0ad2SJack F Vogel * any PHY registers
32628cfa0ad2SJack F Vogel */
32639d81738fSJack F Vogel if (hw->mac.type == e1000_ich8lan)
32648cfa0ad2SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw);
32658cfa0ad2SJack F Vogel
32668cfa0ad2SJack F Vogel /* When LPLU is enabled, we should disable SmartSpeed */
32678cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw,
32688cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG,
32698cfa0ad2SJack F Vogel &data);
32706ab6bfe3SJack F Vogel if (ret_val)
32716ab6bfe3SJack F Vogel return ret_val;
32728cfa0ad2SJack F Vogel data &= ~IGP01E1000_PSCFR_SMART_SPEED;
32738cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw,
32748cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG,
32758cfa0ad2SJack F Vogel data);
32768cfa0ad2SJack F Vogel if (ret_val)
32776ab6bfe3SJack F Vogel return ret_val;
32788cfa0ad2SJack F Vogel } else {
32798cfa0ad2SJack F Vogel phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
32808cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
32818cfa0ad2SJack F Vogel
32829d81738fSJack F Vogel if (phy->type != e1000_phy_igp_3)
32836ab6bfe3SJack F Vogel return E1000_SUCCESS;
32849d81738fSJack F Vogel
32856ab6bfe3SJack F Vogel /* LPLU and SmartSpeed are mutually exclusive. LPLU is used
32868cfa0ad2SJack F Vogel * during Dx states where the power conservation is most
32878cfa0ad2SJack F Vogel * important. During driver activity we should enable
32888cfa0ad2SJack F Vogel * SmartSpeed, so performance is maintained.
32898cfa0ad2SJack F Vogel */
32908cfa0ad2SJack F Vogel if (phy->smart_speed == e1000_smart_speed_on) {
32918cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw,
32928cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG,
32938cfa0ad2SJack F Vogel &data);
32948cfa0ad2SJack F Vogel if (ret_val)
32956ab6bfe3SJack F Vogel return ret_val;
32968cfa0ad2SJack F Vogel
32978cfa0ad2SJack F Vogel data |= IGP01E1000_PSCFR_SMART_SPEED;
32988cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw,
32998cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG,
33008cfa0ad2SJack F Vogel data);
33018cfa0ad2SJack F Vogel if (ret_val)
33026ab6bfe3SJack F Vogel return ret_val;
33038cfa0ad2SJack F Vogel } else if (phy->smart_speed == e1000_smart_speed_off) {
33048cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw,
33058cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG,
33068cfa0ad2SJack F Vogel &data);
33078cfa0ad2SJack F Vogel if (ret_val)
33086ab6bfe3SJack F Vogel return ret_val;
33098cfa0ad2SJack F Vogel
33108cfa0ad2SJack F Vogel data &= ~IGP01E1000_PSCFR_SMART_SPEED;
33118cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw,
33128cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG,
33138cfa0ad2SJack F Vogel data);
33148cfa0ad2SJack F Vogel if (ret_val)
33156ab6bfe3SJack F Vogel return ret_val;
33168cfa0ad2SJack F Vogel }
33178cfa0ad2SJack F Vogel }
33188cfa0ad2SJack F Vogel
33196ab6bfe3SJack F Vogel return E1000_SUCCESS;
33208cfa0ad2SJack F Vogel }
33218cfa0ad2SJack F Vogel
33228cfa0ad2SJack F Vogel /**
33238cfa0ad2SJack F Vogel * e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state
33248cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
33251bbdc25fSKevin Bowling * @active: true to enable LPLU, false to disable
33268cfa0ad2SJack F Vogel *
33278cfa0ad2SJack F Vogel * Sets the LPLU D3 state according to the active flag. When
33288cfa0ad2SJack F Vogel * activating LPLU this function also disables smart speed
33298cfa0ad2SJack F Vogel * and vice versa. LPLU will not be activated unless the
33308cfa0ad2SJack F Vogel * device autonegotiation advertisement meets standards of
33318cfa0ad2SJack F Vogel * either 10 or 10/100 or 10/100/1000 at all duplexes.
33328cfa0ad2SJack F Vogel * This is a function pointer entry point only called by
33338cfa0ad2SJack F Vogel * PHY setup routines.
33348cfa0ad2SJack F Vogel **/
e1000_set_d3_lplu_state_ich8lan(struct e1000_hw * hw,bool active)3335daf9197cSJack F Vogel static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
33368cfa0ad2SJack F Vogel {
33378cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy;
33388cfa0ad2SJack F Vogel u32 phy_ctrl;
33398cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS;
33408cfa0ad2SJack F Vogel u16 data;
33418cfa0ad2SJack F Vogel
33428cfa0ad2SJack F Vogel DEBUGFUNC("e1000_set_d3_lplu_state_ich8lan");
33438cfa0ad2SJack F Vogel
33448cfa0ad2SJack F Vogel phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
33458cfa0ad2SJack F Vogel
33468cfa0ad2SJack F Vogel if (!active) {
33478cfa0ad2SJack F Vogel phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
33488cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
33499d81738fSJack F Vogel
33509d81738fSJack F Vogel if (phy->type != e1000_phy_igp_3)
33516ab6bfe3SJack F Vogel return E1000_SUCCESS;
33529d81738fSJack F Vogel
33536ab6bfe3SJack F Vogel /* LPLU and SmartSpeed are mutually exclusive. LPLU is used
33548cfa0ad2SJack F Vogel * during Dx states where the power conservation is most
33558cfa0ad2SJack F Vogel * important. During driver activity we should enable
33568cfa0ad2SJack F Vogel * SmartSpeed, so performance is maintained.
33578cfa0ad2SJack F Vogel */
33588cfa0ad2SJack F Vogel if (phy->smart_speed == e1000_smart_speed_on) {
33598cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw,
33608cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG,
33618cfa0ad2SJack F Vogel &data);
33628cfa0ad2SJack F Vogel if (ret_val)
33636ab6bfe3SJack F Vogel return ret_val;
33648cfa0ad2SJack F Vogel
33658cfa0ad2SJack F Vogel data |= IGP01E1000_PSCFR_SMART_SPEED;
33668cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw,
33678cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG,
33688cfa0ad2SJack F Vogel data);
33698cfa0ad2SJack F Vogel if (ret_val)
33706ab6bfe3SJack F Vogel return ret_val;
33718cfa0ad2SJack F Vogel } else if (phy->smart_speed == e1000_smart_speed_off) {
33728cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw,
33738cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG,
33748cfa0ad2SJack F Vogel &data);
33758cfa0ad2SJack F Vogel if (ret_val)
33766ab6bfe3SJack F Vogel return ret_val;
33778cfa0ad2SJack F Vogel
33788cfa0ad2SJack F Vogel data &= ~IGP01E1000_PSCFR_SMART_SPEED;
33798cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw,
33808cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG,
33818cfa0ad2SJack F Vogel data);
33828cfa0ad2SJack F Vogel if (ret_val)
33836ab6bfe3SJack F Vogel return ret_val;
33848cfa0ad2SJack F Vogel }
33858cfa0ad2SJack F Vogel } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
33868cfa0ad2SJack F Vogel (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
33878cfa0ad2SJack F Vogel (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
33888cfa0ad2SJack F Vogel phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
33898cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
33908cfa0ad2SJack F Vogel
33919d81738fSJack F Vogel if (phy->type != e1000_phy_igp_3)
33926ab6bfe3SJack F Vogel return E1000_SUCCESS;
33939d81738fSJack F Vogel
33946ab6bfe3SJack F Vogel /* Call gig speed drop workaround on LPLU before accessing
33958cfa0ad2SJack F Vogel * any PHY registers
33968cfa0ad2SJack F Vogel */
33979d81738fSJack F Vogel if (hw->mac.type == e1000_ich8lan)
33988cfa0ad2SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw);
33998cfa0ad2SJack F Vogel
34008cfa0ad2SJack F Vogel /* When LPLU is enabled, we should disable SmartSpeed */
34018cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw,
34028cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG,
34038cfa0ad2SJack F Vogel &data);
34048cfa0ad2SJack F Vogel if (ret_val)
34056ab6bfe3SJack F Vogel return ret_val;
34068cfa0ad2SJack F Vogel
34078cfa0ad2SJack F Vogel data &= ~IGP01E1000_PSCFR_SMART_SPEED;
34088cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw,
34098cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG,
34108cfa0ad2SJack F Vogel data);
34118cfa0ad2SJack F Vogel }
34128cfa0ad2SJack F Vogel
34138cfa0ad2SJack F Vogel return ret_val;
34148cfa0ad2SJack F Vogel }
34158cfa0ad2SJack F Vogel
34168cfa0ad2SJack F Vogel /**
34178cfa0ad2SJack F Vogel * e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1
34188cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
34198cfa0ad2SJack F Vogel * @bank: pointer to the variable that returns the active bank
34208cfa0ad2SJack F Vogel *
34218cfa0ad2SJack F Vogel * Reads signature byte from the NVM using the flash access registers.
3422d035aa2dSJack F Vogel * Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank.
34238cfa0ad2SJack F Vogel **/
e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw * hw,u32 * bank)34248cfa0ad2SJack F Vogel static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
34258cfa0ad2SJack F Vogel {
3426d035aa2dSJack F Vogel u32 eecd;
34278cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm;
34288cfa0ad2SJack F Vogel u32 bank1_offset = nvm->flash_bank_size * sizeof(u16);
34298cfa0ad2SJack F Vogel u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
3430c80429ceSEric Joyner u32 nvm_dword = 0;
3431d035aa2dSJack F Vogel u8 sig_byte = 0;
34326ab6bfe3SJack F Vogel s32 ret_val;
34338cfa0ad2SJack F Vogel
34347d9119bdSJack F Vogel DEBUGFUNC("e1000_valid_nvm_bank_detect_ich8lan");
34357d9119bdSJack F Vogel
3436d035aa2dSJack F Vogel switch (hw->mac.type) {
3437c80429ceSEric Joyner case e1000_pch_spt:
34386fe4c0a0SSean Bruno case e1000_pch_cnp:
343959690eabSKevin Bowling case e1000_pch_tgp:
344059690eabSKevin Bowling case e1000_pch_adp:
344159690eabSKevin Bowling case e1000_pch_mtp:
3442*905ae588SKevin Bowling case e1000_pch_ptp:
3443c80429ceSEric Joyner bank1_offset = nvm->flash_bank_size;
3444c80429ceSEric Joyner act_offset = E1000_ICH_NVM_SIG_WORD;
3445c80429ceSEric Joyner
3446c80429ceSEric Joyner /* set bank to 0 in case flash read fails */
3447c80429ceSEric Joyner *bank = 0;
3448c80429ceSEric Joyner
3449c80429ceSEric Joyner /* Check bank 0 */
3450c80429ceSEric Joyner ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset,
3451c80429ceSEric Joyner &nvm_dword);
3452c80429ceSEric Joyner if (ret_val)
3453c80429ceSEric Joyner return ret_val;
3454c80429ceSEric Joyner sig_byte = (u8)((nvm_dword & 0xFF00) >> 8);
3455c80429ceSEric Joyner if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
3456c80429ceSEric Joyner E1000_ICH_NVM_SIG_VALUE) {
3457c80429ceSEric Joyner *bank = 0;
3458c80429ceSEric Joyner return E1000_SUCCESS;
3459c80429ceSEric Joyner }
3460c80429ceSEric Joyner
3461c80429ceSEric Joyner /* Check bank 1 */
3462c80429ceSEric Joyner ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset +
3463c80429ceSEric Joyner bank1_offset,
3464c80429ceSEric Joyner &nvm_dword);
3465c80429ceSEric Joyner if (ret_val)
3466c80429ceSEric Joyner return ret_val;
3467c80429ceSEric Joyner sig_byte = (u8)((nvm_dword & 0xFF00) >> 8);
3468c80429ceSEric Joyner if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
3469c80429ceSEric Joyner E1000_ICH_NVM_SIG_VALUE) {
3470c80429ceSEric Joyner *bank = 1;
3471c80429ceSEric Joyner return E1000_SUCCESS;
3472c80429ceSEric Joyner }
3473c80429ceSEric Joyner
3474c80429ceSEric Joyner DEBUGOUT("ERROR: No valid NVM bank present\n");
3475c80429ceSEric Joyner return -E1000_ERR_NVM;
3476d035aa2dSJack F Vogel case e1000_ich8lan:
3477d035aa2dSJack F Vogel case e1000_ich9lan:
3478d035aa2dSJack F Vogel eecd = E1000_READ_REG(hw, E1000_EECD);
3479d035aa2dSJack F Vogel if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) ==
3480d035aa2dSJack F Vogel E1000_EECD_SEC1VAL_VALID_MASK) {
3481d035aa2dSJack F Vogel if (eecd & E1000_EECD_SEC1VAL)
34828cfa0ad2SJack F Vogel *bank = 1;
34838cfa0ad2SJack F Vogel else
34848cfa0ad2SJack F Vogel *bank = 0;
3485d035aa2dSJack F Vogel
34866ab6bfe3SJack F Vogel return E1000_SUCCESS;
3487d035aa2dSJack F Vogel }
34884dab5c37SJack F Vogel DEBUGOUT("Unable to determine valid NVM bank via EEC - reading flash signature\n");
3489e05d9788SKevin Bowling /* FALLTHROUGH */
3490d035aa2dSJack F Vogel default:
3491d035aa2dSJack F Vogel /* set bank to 0 in case flash read fails */
34928cfa0ad2SJack F Vogel *bank = 0;
34938cfa0ad2SJack F Vogel
3494d035aa2dSJack F Vogel /* Check bank 0 */
3495d035aa2dSJack F Vogel ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset,
3496d035aa2dSJack F Vogel &sig_byte);
3497d035aa2dSJack F Vogel if (ret_val)
34986ab6bfe3SJack F Vogel return ret_val;
3499d035aa2dSJack F Vogel if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
3500d035aa2dSJack F Vogel E1000_ICH_NVM_SIG_VALUE) {
3501d035aa2dSJack F Vogel *bank = 0;
35026ab6bfe3SJack F Vogel return E1000_SUCCESS;
3503d035aa2dSJack F Vogel }
3504d035aa2dSJack F Vogel
3505d035aa2dSJack F Vogel /* Check bank 1 */
3506d035aa2dSJack F Vogel ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset +
3507d035aa2dSJack F Vogel bank1_offset,
3508d035aa2dSJack F Vogel &sig_byte);
3509d035aa2dSJack F Vogel if (ret_val)
35106ab6bfe3SJack F Vogel return ret_val;
3511d035aa2dSJack F Vogel if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
3512d035aa2dSJack F Vogel E1000_ICH_NVM_SIG_VALUE) {
35138cfa0ad2SJack F Vogel *bank = 1;
35146ab6bfe3SJack F Vogel return E1000_SUCCESS;
35158cfa0ad2SJack F Vogel }
35168cfa0ad2SJack F Vogel
3517d035aa2dSJack F Vogel DEBUGOUT("ERROR: No valid NVM bank present\n");
35186ab6bfe3SJack F Vogel return -E1000_ERR_NVM;
3519d035aa2dSJack F Vogel }
35208cfa0ad2SJack F Vogel }
35218cfa0ad2SJack F Vogel
35228cfa0ad2SJack F Vogel /**
3523c80429ceSEric Joyner * e1000_read_nvm_spt - NVM access for SPT
3524c80429ceSEric Joyner * @hw: pointer to the HW structure
3525c80429ceSEric Joyner * @offset: The offset (in bytes) of the word(s) to read.
3526c80429ceSEric Joyner * @words: Size of data to read in words.
3527c80429ceSEric Joyner * @data: pointer to the word(s) to read at offset.
3528c80429ceSEric Joyner *
3529c80429ceSEric Joyner * Reads a word(s) from the NVM
3530c80429ceSEric Joyner **/
e1000_read_nvm_spt(struct e1000_hw * hw,u16 offset,u16 words,u16 * data)3531c80429ceSEric Joyner static s32 e1000_read_nvm_spt(struct e1000_hw *hw, u16 offset, u16 words,
3532c80429ceSEric Joyner u16 *data)
3533c80429ceSEric Joyner {
3534c80429ceSEric Joyner struct e1000_nvm_info *nvm = &hw->nvm;
3535c80429ceSEric Joyner struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
3536c80429ceSEric Joyner u32 act_offset;
3537c80429ceSEric Joyner s32 ret_val = E1000_SUCCESS;
3538c80429ceSEric Joyner u32 bank = 0;
3539c80429ceSEric Joyner u32 dword = 0;
3540c80429ceSEric Joyner u16 offset_to_read;
3541c80429ceSEric Joyner u16 i;
3542c80429ceSEric Joyner
3543c80429ceSEric Joyner DEBUGFUNC("e1000_read_nvm_spt");
3544c80429ceSEric Joyner
3545c80429ceSEric Joyner if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
3546c80429ceSEric Joyner (words == 0)) {
3547c80429ceSEric Joyner DEBUGOUT("nvm parameter(s) out of bounds\n");
3548c80429ceSEric Joyner ret_val = -E1000_ERR_NVM;
3549c80429ceSEric Joyner goto out;
3550c80429ceSEric Joyner }
3551c80429ceSEric Joyner
3552c80429ceSEric Joyner nvm->ops.acquire(hw);
3553c80429ceSEric Joyner
3554c80429ceSEric Joyner ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
3555c80429ceSEric Joyner if (ret_val != E1000_SUCCESS) {
3556c80429ceSEric Joyner DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
3557c80429ceSEric Joyner bank = 0;
3558c80429ceSEric Joyner }
3559c80429ceSEric Joyner
3560c80429ceSEric Joyner act_offset = (bank) ? nvm->flash_bank_size : 0;
3561c80429ceSEric Joyner act_offset += offset;
3562c80429ceSEric Joyner
3563c80429ceSEric Joyner ret_val = E1000_SUCCESS;
3564c80429ceSEric Joyner
3565c80429ceSEric Joyner for (i = 0; i < words; i += 2) {
3566c80429ceSEric Joyner if (words - i == 1) {
3567c80429ceSEric Joyner if (dev_spec->shadow_ram[offset + i].modified) {
35686c59e186SGuinan Sun data[i] =
35696c59e186SGuinan Sun dev_spec->shadow_ram[offset + i].value;
3570c80429ceSEric Joyner } else {
3571c80429ceSEric Joyner offset_to_read = act_offset + i -
3572c80429ceSEric Joyner ((act_offset + i) % 2);
3573c80429ceSEric Joyner ret_val =
3574c80429ceSEric Joyner e1000_read_flash_dword_ich8lan(hw,
3575c80429ceSEric Joyner offset_to_read,
3576c80429ceSEric Joyner &dword);
3577c80429ceSEric Joyner if (ret_val)
3578c80429ceSEric Joyner break;
3579c80429ceSEric Joyner if ((act_offset + i) % 2 == 0)
3580c80429ceSEric Joyner data[i] = (u16)(dword & 0xFFFF);
3581c80429ceSEric Joyner else
3582c80429ceSEric Joyner data[i] = (u16)((dword >> 16) & 0xFFFF);
3583c80429ceSEric Joyner }
3584c80429ceSEric Joyner } else {
3585c80429ceSEric Joyner offset_to_read = act_offset + i;
3586c80429ceSEric Joyner if (!(dev_spec->shadow_ram[offset + i].modified) ||
3587c80429ceSEric Joyner !(dev_spec->shadow_ram[offset + i + 1].modified)) {
3588c80429ceSEric Joyner ret_val =
3589c80429ceSEric Joyner e1000_read_flash_dword_ich8lan(hw,
3590c80429ceSEric Joyner offset_to_read,
3591c80429ceSEric Joyner &dword);
3592c80429ceSEric Joyner if (ret_val)
3593c80429ceSEric Joyner break;
3594c80429ceSEric Joyner }
3595c80429ceSEric Joyner if (dev_spec->shadow_ram[offset + i].modified)
35966c59e186SGuinan Sun data[i] =
35976c59e186SGuinan Sun dev_spec->shadow_ram[offset + i].value;
3598c80429ceSEric Joyner else
3599c80429ceSEric Joyner data[i] = (u16)(dword & 0xFFFF);
36006c59e186SGuinan Sun if (dev_spec->shadow_ram[offset + i + 1].modified)
3601c80429ceSEric Joyner data[i + 1] =
3602c80429ceSEric Joyner dev_spec->shadow_ram[offset + i + 1].value;
3603c80429ceSEric Joyner else
3604c80429ceSEric Joyner data[i + 1] = (u16)(dword >> 16 & 0xFFFF);
3605c80429ceSEric Joyner }
3606c80429ceSEric Joyner }
3607c80429ceSEric Joyner
3608c80429ceSEric Joyner nvm->ops.release(hw);
3609c80429ceSEric Joyner
3610c80429ceSEric Joyner out:
3611c80429ceSEric Joyner if (ret_val)
3612c80429ceSEric Joyner DEBUGOUT1("NVM read error: %d\n", ret_val);
3613c80429ceSEric Joyner
3614c80429ceSEric Joyner return ret_val;
3615c80429ceSEric Joyner }
3616c80429ceSEric Joyner
3617c80429ceSEric Joyner /**
36188cfa0ad2SJack F Vogel * e1000_read_nvm_ich8lan - Read word(s) from the NVM
36198cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
36208cfa0ad2SJack F Vogel * @offset: The offset (in bytes) of the word(s) to read.
36218cfa0ad2SJack F Vogel * @words: Size of data to read in words
36228cfa0ad2SJack F Vogel * @data: Pointer to the word(s) to read at offset.
36238cfa0ad2SJack F Vogel *
36248cfa0ad2SJack F Vogel * Reads a word(s) from the NVM using the flash access registers.
36258cfa0ad2SJack F Vogel **/
e1000_read_nvm_ich8lan(struct e1000_hw * hw,u16 offset,u16 words,u16 * data)36268cfa0ad2SJack F Vogel static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
36278cfa0ad2SJack F Vogel u16 *data)
36288cfa0ad2SJack F Vogel {
36298cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm;
3630daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
36318cfa0ad2SJack F Vogel u32 act_offset;
36328cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS;
36338cfa0ad2SJack F Vogel u32 bank = 0;
36348cfa0ad2SJack F Vogel u16 i, word;
36358cfa0ad2SJack F Vogel
36368cfa0ad2SJack F Vogel DEBUGFUNC("e1000_read_nvm_ich8lan");
36378cfa0ad2SJack F Vogel
36388cfa0ad2SJack F Vogel if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
36398cfa0ad2SJack F Vogel (words == 0)) {
36408cfa0ad2SJack F Vogel DEBUGOUT("nvm parameter(s) out of bounds\n");
36418cfa0ad2SJack F Vogel ret_val = -E1000_ERR_NVM;
36428cfa0ad2SJack F Vogel goto out;
36438cfa0ad2SJack F Vogel }
36448cfa0ad2SJack F Vogel
36454edd8523SJack F Vogel nvm->ops.acquire(hw);
36468cfa0ad2SJack F Vogel
36478cfa0ad2SJack F Vogel ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
36484edd8523SJack F Vogel if (ret_val != E1000_SUCCESS) {
36494edd8523SJack F Vogel DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
36504edd8523SJack F Vogel bank = 0;
36514edd8523SJack F Vogel }
36528cfa0ad2SJack F Vogel
36538cfa0ad2SJack F Vogel act_offset = (bank) ? nvm->flash_bank_size : 0;
36548cfa0ad2SJack F Vogel act_offset += offset;
36558cfa0ad2SJack F Vogel
36564edd8523SJack F Vogel ret_val = E1000_SUCCESS;
36578cfa0ad2SJack F Vogel for (i = 0; i < words; i++) {
36584dab5c37SJack F Vogel if (dev_spec->shadow_ram[offset + i].modified) {
36598cfa0ad2SJack F Vogel data[i] = dev_spec->shadow_ram[offset + i].value;
36608cfa0ad2SJack F Vogel } else {
36618cfa0ad2SJack F Vogel ret_val = e1000_read_flash_word_ich8lan(hw,
36628cfa0ad2SJack F Vogel act_offset + i,
36638cfa0ad2SJack F Vogel &word);
36648cfa0ad2SJack F Vogel if (ret_val)
36658cfa0ad2SJack F Vogel break;
36668cfa0ad2SJack F Vogel data[i] = word;
36678cfa0ad2SJack F Vogel }
36688cfa0ad2SJack F Vogel }
36698cfa0ad2SJack F Vogel
36708cfa0ad2SJack F Vogel nvm->ops.release(hw);
36718cfa0ad2SJack F Vogel
36728cfa0ad2SJack F Vogel out:
3673d035aa2dSJack F Vogel if (ret_val)
3674d035aa2dSJack F Vogel DEBUGOUT1("NVM read error: %d\n", ret_val);
3675d035aa2dSJack F Vogel
36768cfa0ad2SJack F Vogel return ret_val;
36778cfa0ad2SJack F Vogel }
36788cfa0ad2SJack F Vogel
36798cfa0ad2SJack F Vogel /**
36808cfa0ad2SJack F Vogel * e1000_flash_cycle_init_ich8lan - Initialize flash
36818cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
36828cfa0ad2SJack F Vogel *
36838cfa0ad2SJack F Vogel * This function does initial flash setup so that a new read/write/erase cycle
36848cfa0ad2SJack F Vogel * can be started.
36858cfa0ad2SJack F Vogel **/
e1000_flash_cycle_init_ich8lan(struct e1000_hw * hw)36868cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
36878cfa0ad2SJack F Vogel {
36888cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts;
36898cfa0ad2SJack F Vogel s32 ret_val = -E1000_ERR_NVM;
36908cfa0ad2SJack F Vogel
36918cfa0ad2SJack F Vogel DEBUGFUNC("e1000_flash_cycle_init_ich8lan");
36928cfa0ad2SJack F Vogel
36938cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
36948cfa0ad2SJack F Vogel
36958cfa0ad2SJack F Vogel /* Check if the flash descriptor is valid */
36966ab6bfe3SJack F Vogel if (!hsfsts.hsf_status.fldesvalid) {
36974dab5c37SJack F Vogel DEBUGOUT("Flash descriptor invalid. SW Sequencing must be used.\n");
36986ab6bfe3SJack F Vogel return -E1000_ERR_NVM;
36998cfa0ad2SJack F Vogel }
37008cfa0ad2SJack F Vogel
37018cfa0ad2SJack F Vogel /* Clear FCERR and DAEL in hw status by writing 1 */
37028cfa0ad2SJack F Vogel hsfsts.hsf_status.flcerr = 1;
37038cfa0ad2SJack F Vogel hsfsts.hsf_status.dael = 1;
3704295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt)
3705c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
3706c80429ceSEric Joyner hsfsts.regval & 0xFFFF);
3707c80429ceSEric Joyner else
37088cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
37098cfa0ad2SJack F Vogel
37106ab6bfe3SJack F Vogel /* Either we should have a hardware SPI cycle in progress
37118cfa0ad2SJack F Vogel * bit to check against, in order to start a new cycle or
37128cfa0ad2SJack F Vogel * FDONE bit should be changed in the hardware so that it
37138cfa0ad2SJack F Vogel * is 1 after hardware reset, which can then be used as an
37148cfa0ad2SJack F Vogel * indication whether a cycle is in progress or has been
37158cfa0ad2SJack F Vogel * completed.
37168cfa0ad2SJack F Vogel */
37178cfa0ad2SJack F Vogel
37186ab6bfe3SJack F Vogel if (!hsfsts.hsf_status.flcinprog) {
37196ab6bfe3SJack F Vogel /* There is no cycle running at present,
37208cfa0ad2SJack F Vogel * so we can start a cycle.
37218cfa0ad2SJack F Vogel * Begin by setting Flash Cycle Done.
37228cfa0ad2SJack F Vogel */
37238cfa0ad2SJack F Vogel hsfsts.hsf_status.flcdone = 1;
3724295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt)
3725c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
3726c80429ceSEric Joyner hsfsts.regval & 0xFFFF);
3727c80429ceSEric Joyner else
3728c80429ceSEric Joyner E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS,
3729c80429ceSEric Joyner hsfsts.regval);
37308cfa0ad2SJack F Vogel ret_val = E1000_SUCCESS;
37318cfa0ad2SJack F Vogel } else {
3732730d3130SJack F Vogel s32 i;
3733730d3130SJack F Vogel
37346ab6bfe3SJack F Vogel /* Otherwise poll for sometime so the current
37358cfa0ad2SJack F Vogel * cycle has a chance to end before giving up.
37368cfa0ad2SJack F Vogel */
37378cfa0ad2SJack F Vogel for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) {
37388cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw,
37398cfa0ad2SJack F Vogel ICH_FLASH_HSFSTS);
37406ab6bfe3SJack F Vogel if (!hsfsts.hsf_status.flcinprog) {
37418cfa0ad2SJack F Vogel ret_val = E1000_SUCCESS;
37428cfa0ad2SJack F Vogel break;
37438cfa0ad2SJack F Vogel }
37448cfa0ad2SJack F Vogel usec_delay(1);
37458cfa0ad2SJack F Vogel }
37468cfa0ad2SJack F Vogel if (ret_val == E1000_SUCCESS) {
37476ab6bfe3SJack F Vogel /* Successful in waiting for previous cycle to timeout,
37488cfa0ad2SJack F Vogel * now set the Flash Cycle Done.
37498cfa0ad2SJack F Vogel */
37508cfa0ad2SJack F Vogel hsfsts.hsf_status.flcdone = 1;
3751295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt)
3752c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
3753c80429ceSEric Joyner hsfsts.regval & 0xFFFF);
3754c80429ceSEric Joyner else
3755daf9197cSJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS,
37568cfa0ad2SJack F Vogel hsfsts.regval);
37578cfa0ad2SJack F Vogel } else {
37584dab5c37SJack F Vogel DEBUGOUT("Flash controller busy, cannot get access\n");
37598cfa0ad2SJack F Vogel }
37608cfa0ad2SJack F Vogel }
37618cfa0ad2SJack F Vogel
37628cfa0ad2SJack F Vogel return ret_val;
37638cfa0ad2SJack F Vogel }
37648cfa0ad2SJack F Vogel
37658cfa0ad2SJack F Vogel /**
37668cfa0ad2SJack F Vogel * e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase)
37678cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
37688cfa0ad2SJack F Vogel * @timeout: maximum time to wait for completion
37698cfa0ad2SJack F Vogel *
37708cfa0ad2SJack F Vogel * This function starts a flash cycle and waits for its completion.
37718cfa0ad2SJack F Vogel **/
e1000_flash_cycle_ich8lan(struct e1000_hw * hw,u32 timeout)37728cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout)
37738cfa0ad2SJack F Vogel {
37748cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl hsflctl;
37758cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts;
37768cfa0ad2SJack F Vogel u32 i = 0;
37778cfa0ad2SJack F Vogel
37788cfa0ad2SJack F Vogel DEBUGFUNC("e1000_flash_cycle_ich8lan");
37798cfa0ad2SJack F Vogel
37808cfa0ad2SJack F Vogel /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
3781295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt)
3782c80429ceSEric Joyner hsflctl.regval = E1000_READ_FLASH_REG(hw, ICH_FLASH_HSFSTS)>>16;
3783c80429ceSEric Joyner else
37848cfa0ad2SJack F Vogel hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
37858cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.flcgo = 1;
37868cc64f1eSJack F Vogel
3787295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt)
3788c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
3789c80429ceSEric Joyner hsflctl.regval << 16);
3790c80429ceSEric Joyner else
37918cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
37928cfa0ad2SJack F Vogel
37938cfa0ad2SJack F Vogel /* wait till FDONE bit is set to 1 */
37948cfa0ad2SJack F Vogel do {
37958cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
37966ab6bfe3SJack F Vogel if (hsfsts.hsf_status.flcdone)
37978cfa0ad2SJack F Vogel break;
37988cfa0ad2SJack F Vogel usec_delay(1);
37998cfa0ad2SJack F Vogel } while (i++ < timeout);
38008cfa0ad2SJack F Vogel
38016ab6bfe3SJack F Vogel if (hsfsts.hsf_status.flcdone && !hsfsts.hsf_status.flcerr)
38026ab6bfe3SJack F Vogel return E1000_SUCCESS;
38038cfa0ad2SJack F Vogel
38046ab6bfe3SJack F Vogel return -E1000_ERR_NVM;
38058cfa0ad2SJack F Vogel }
38068cfa0ad2SJack F Vogel
38078cfa0ad2SJack F Vogel /**
3808c80429ceSEric Joyner * e1000_read_flash_dword_ich8lan - Read dword from flash
3809c80429ceSEric Joyner * @hw: pointer to the HW structure
3810c80429ceSEric Joyner * @offset: offset to data location
3811c80429ceSEric Joyner * @data: pointer to the location for storing the data
3812c80429ceSEric Joyner *
3813c80429ceSEric Joyner * Reads the flash dword at offset into data. Offset is converted
3814c80429ceSEric Joyner * to bytes before read.
3815c80429ceSEric Joyner **/
e1000_read_flash_dword_ich8lan(struct e1000_hw * hw,u32 offset,u32 * data)3816c80429ceSEric Joyner static s32 e1000_read_flash_dword_ich8lan(struct e1000_hw *hw, u32 offset,
3817c80429ceSEric Joyner u32 *data)
3818c80429ceSEric Joyner {
3819c80429ceSEric Joyner DEBUGFUNC("e1000_read_flash_dword_ich8lan");
3820c80429ceSEric Joyner
3821c80429ceSEric Joyner if (!data)
3822c80429ceSEric Joyner return -E1000_ERR_NVM;
3823c80429ceSEric Joyner
3824c80429ceSEric Joyner /* Must convert word offset into bytes. */
3825c80429ceSEric Joyner offset <<= 1;
3826c80429ceSEric Joyner
3827c80429ceSEric Joyner return e1000_read_flash_data32_ich8lan(hw, offset, data);
3828c80429ceSEric Joyner }
3829c80429ceSEric Joyner
3830c80429ceSEric Joyner /**
38318cfa0ad2SJack F Vogel * e1000_read_flash_word_ich8lan - Read word from flash
38328cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
38338cfa0ad2SJack F Vogel * @offset: offset to data location
38348cfa0ad2SJack F Vogel * @data: pointer to the location for storing the data
38358cfa0ad2SJack F Vogel *
38368cfa0ad2SJack F Vogel * Reads the flash word at offset into data. Offset is converted
38378cfa0ad2SJack F Vogel * to bytes before read.
38388cfa0ad2SJack F Vogel **/
e1000_read_flash_word_ich8lan(struct e1000_hw * hw,u32 offset,u16 * data)38398cfa0ad2SJack F Vogel static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
38408cfa0ad2SJack F Vogel u16 *data)
38418cfa0ad2SJack F Vogel {
38428cfa0ad2SJack F Vogel DEBUGFUNC("e1000_read_flash_word_ich8lan");
38438cfa0ad2SJack F Vogel
38446ab6bfe3SJack F Vogel if (!data)
38456ab6bfe3SJack F Vogel return -E1000_ERR_NVM;
38468cfa0ad2SJack F Vogel
38478cfa0ad2SJack F Vogel /* Must convert offset into bytes. */
38488cfa0ad2SJack F Vogel offset <<= 1;
38498cfa0ad2SJack F Vogel
38506ab6bfe3SJack F Vogel return e1000_read_flash_data_ich8lan(hw, offset, 2, data);
38518cfa0ad2SJack F Vogel }
38528cfa0ad2SJack F Vogel
38538cfa0ad2SJack F Vogel /**
38548cfa0ad2SJack F Vogel * e1000_read_flash_byte_ich8lan - Read byte from flash
38558cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
38568cfa0ad2SJack F Vogel * @offset: The offset of the byte to read.
38578cfa0ad2SJack F Vogel * @data: Pointer to a byte to store the value read.
38588cfa0ad2SJack F Vogel *
38598cfa0ad2SJack F Vogel * Reads a single byte from the NVM using the flash access registers.
38608cfa0ad2SJack F Vogel **/
e1000_read_flash_byte_ich8lan(struct e1000_hw * hw,u32 offset,u8 * data)38618cfa0ad2SJack F Vogel static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
38628cfa0ad2SJack F Vogel u8 *data)
38638cfa0ad2SJack F Vogel {
38646ab6bfe3SJack F Vogel s32 ret_val;
38658cfa0ad2SJack F Vogel u16 word = 0;
38668cfa0ad2SJack F Vogel
3867c80429ceSEric Joyner /* In SPT, only 32 bits access is supported,
3868c80429ceSEric Joyner * so this function should not be called.
3869c80429ceSEric Joyner */
3870295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt)
3871c80429ceSEric Joyner return -E1000_ERR_NVM;
3872c80429ceSEric Joyner else
38738cfa0ad2SJack F Vogel ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word);
38748cc64f1eSJack F Vogel
38758cfa0ad2SJack F Vogel if (ret_val)
38766ab6bfe3SJack F Vogel return ret_val;
38778cfa0ad2SJack F Vogel
38788cfa0ad2SJack F Vogel *data = (u8)word;
38798cfa0ad2SJack F Vogel
38806ab6bfe3SJack F Vogel return E1000_SUCCESS;
38818cfa0ad2SJack F Vogel }
38828cfa0ad2SJack F Vogel
38838cfa0ad2SJack F Vogel /**
38848cfa0ad2SJack F Vogel * e1000_read_flash_data_ich8lan - Read byte or word from NVM
38858cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
38868cfa0ad2SJack F Vogel * @offset: The offset (in bytes) of the byte or word to read.
38878cfa0ad2SJack F Vogel * @size: Size of data to read, 1=byte 2=word
38888cfa0ad2SJack F Vogel * @data: Pointer to the word to store the value read.
38898cfa0ad2SJack F Vogel *
38908cfa0ad2SJack F Vogel * Reads a byte or word from the NVM using the flash access registers.
38918cfa0ad2SJack F Vogel **/
e1000_read_flash_data_ich8lan(struct e1000_hw * hw,u32 offset,u8 size,u16 * data)38928cfa0ad2SJack F Vogel static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
38938cfa0ad2SJack F Vogel u8 size, u16 *data)
38948cfa0ad2SJack F Vogel {
38958cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts;
38968cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl hsflctl;
38978cfa0ad2SJack F Vogel u32 flash_linear_addr;
38988cfa0ad2SJack F Vogel u32 flash_data = 0;
38998cfa0ad2SJack F Vogel s32 ret_val = -E1000_ERR_NVM;
39008cfa0ad2SJack F Vogel u8 count = 0;
39018cfa0ad2SJack F Vogel
39028cfa0ad2SJack F Vogel DEBUGFUNC("e1000_read_flash_data_ich8lan");
39038cfa0ad2SJack F Vogel
39048cfa0ad2SJack F Vogel if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
39056ab6bfe3SJack F Vogel return -E1000_ERR_NVM;
39067609433eSJack F Vogel flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
39077609433eSJack F Vogel hw->nvm.flash_base_addr);
39088cfa0ad2SJack F Vogel
39098cfa0ad2SJack F Vogel do {
39108cfa0ad2SJack F Vogel usec_delay(1);
39118cfa0ad2SJack F Vogel /* Steps */
39128cfa0ad2SJack F Vogel ret_val = e1000_flash_cycle_init_ich8lan(hw);
39138cfa0ad2SJack F Vogel if (ret_val != E1000_SUCCESS)
39148cfa0ad2SJack F Vogel break;
39158cfa0ad2SJack F Vogel hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
39168cc64f1eSJack F Vogel
39178cfa0ad2SJack F Vogel /* 0b/1b corresponds to 1 or 2 byte size, respectively. */
39188cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.fldbcount = size - 1;
39198cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
39208cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
39218cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
39228cfa0ad2SJack F Vogel
39238cc64f1eSJack F Vogel ret_val = e1000_flash_cycle_ich8lan(hw,
39248cfa0ad2SJack F Vogel ICH_FLASH_READ_COMMAND_TIMEOUT);
39258cfa0ad2SJack F Vogel
39266ab6bfe3SJack F Vogel /* Check if FCERR is set to 1, if set to 1, clear it
39278cfa0ad2SJack F Vogel * and try the whole sequence a few more times, else
39288cfa0ad2SJack F Vogel * read in (shift in) the Flash Data0, the order is
39298cfa0ad2SJack F Vogel * least significant byte first msb to lsb
39308cfa0ad2SJack F Vogel */
39318cfa0ad2SJack F Vogel if (ret_val == E1000_SUCCESS) {
39328cfa0ad2SJack F Vogel flash_data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0);
3933daf9197cSJack F Vogel if (size == 1)
39348cfa0ad2SJack F Vogel *data = (u8)(flash_data & 0x000000FF);
3935daf9197cSJack F Vogel else if (size == 2)
39368cfa0ad2SJack F Vogel *data = (u16)(flash_data & 0x0000FFFF);
39378cfa0ad2SJack F Vogel break;
39388cfa0ad2SJack F Vogel } else {
39396ab6bfe3SJack F Vogel /* If we've gotten here, then things are probably
39408cfa0ad2SJack F Vogel * completely hosed, but if the error condition is
39418cfa0ad2SJack F Vogel * detected, it won't hurt to give it another try...
39428cfa0ad2SJack F Vogel * ICH_FLASH_CYCLE_REPEAT_COUNT times.
39438cfa0ad2SJack F Vogel */
39448cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw,
39458cfa0ad2SJack F Vogel ICH_FLASH_HSFSTS);
39466ab6bfe3SJack F Vogel if (hsfsts.hsf_status.flcerr) {
39478cfa0ad2SJack F Vogel /* Repeat for some time before giving up. */
39488cfa0ad2SJack F Vogel continue;
39496ab6bfe3SJack F Vogel } else if (!hsfsts.hsf_status.flcdone) {
39504dab5c37SJack F Vogel DEBUGOUT("Timeout error - flash cycle did not complete.\n");
39518cfa0ad2SJack F Vogel break;
39528cfa0ad2SJack F Vogel }
39538cfa0ad2SJack F Vogel }
39548cfa0ad2SJack F Vogel } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
39558cfa0ad2SJack F Vogel
39568cfa0ad2SJack F Vogel return ret_val;
39578cfa0ad2SJack F Vogel }
39588cfa0ad2SJack F Vogel
3959c80429ceSEric Joyner /**
3960c80429ceSEric Joyner * e1000_read_flash_data32_ich8lan - Read dword from NVM
3961c80429ceSEric Joyner * @hw: pointer to the HW structure
3962c80429ceSEric Joyner * @offset: The offset (in bytes) of the dword to read.
3963c80429ceSEric Joyner * @data: Pointer to the dword to store the value read.
3964c80429ceSEric Joyner *
3965c80429ceSEric Joyner * Reads a byte or word from the NVM using the flash access registers.
3966c80429ceSEric Joyner **/
e1000_read_flash_data32_ich8lan(struct e1000_hw * hw,u32 offset,u32 * data)3967c80429ceSEric Joyner static s32 e1000_read_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset,
3968c80429ceSEric Joyner u32 *data)
3969c80429ceSEric Joyner {
3970c80429ceSEric Joyner union ich8_hws_flash_status hsfsts;
3971c80429ceSEric Joyner union ich8_hws_flash_ctrl hsflctl;
3972c80429ceSEric Joyner u32 flash_linear_addr;
3973c80429ceSEric Joyner s32 ret_val = -E1000_ERR_NVM;
3974c80429ceSEric Joyner u8 count = 0;
3975c80429ceSEric Joyner
3976c80429ceSEric Joyner DEBUGFUNC("e1000_read_flash_data_ich8lan");
3977c80429ceSEric Joyner
3978c80429ceSEric Joyner if (offset > ICH_FLASH_LINEAR_ADDR_MASK ||
3979295df609SEric Joyner hw->mac.type < e1000_pch_spt)
3980c80429ceSEric Joyner return -E1000_ERR_NVM;
3981c80429ceSEric Joyner flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
3982c80429ceSEric Joyner hw->nvm.flash_base_addr);
3983c80429ceSEric Joyner
3984c80429ceSEric Joyner do {
3985c80429ceSEric Joyner usec_delay(1);
3986c80429ceSEric Joyner /* Steps */
3987c80429ceSEric Joyner ret_val = e1000_flash_cycle_init_ich8lan(hw);
3988c80429ceSEric Joyner if (ret_val != E1000_SUCCESS)
3989c80429ceSEric Joyner break;
3990c80429ceSEric Joyner /* In SPT, This register is in Lan memory space, not flash.
3991c80429ceSEric Joyner * Therefore, only 32 bit access is supported
3992c80429ceSEric Joyner */
3993c80429ceSEric Joyner hsflctl.regval = E1000_READ_FLASH_REG(hw, ICH_FLASH_HSFSTS)>>16;
3994c80429ceSEric Joyner
3995c80429ceSEric Joyner /* 0b/1b corresponds to 1 or 2 byte size, respectively. */
3996c80429ceSEric Joyner hsflctl.hsf_ctrl.fldbcount = sizeof(u32) - 1;
3997c80429ceSEric Joyner hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
3998c80429ceSEric Joyner /* In SPT, This register is in Lan memory space, not flash.
3999c80429ceSEric Joyner * Therefore, only 32 bit access is supported
4000c80429ceSEric Joyner */
4001c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
4002c80429ceSEric Joyner (u32)hsflctl.regval << 16);
4003c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
4004c80429ceSEric Joyner
4005c80429ceSEric Joyner ret_val = e1000_flash_cycle_ich8lan(hw,
4006c80429ceSEric Joyner ICH_FLASH_READ_COMMAND_TIMEOUT);
4007c80429ceSEric Joyner
4008c80429ceSEric Joyner /* Check if FCERR is set to 1, if set to 1, clear it
4009c80429ceSEric Joyner * and try the whole sequence a few more times, else
4010c80429ceSEric Joyner * read in (shift in) the Flash Data0, the order is
4011c80429ceSEric Joyner * least significant byte first msb to lsb
4012c80429ceSEric Joyner */
4013c80429ceSEric Joyner if (ret_val == E1000_SUCCESS) {
4014c80429ceSEric Joyner *data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0);
4015c80429ceSEric Joyner break;
4016c80429ceSEric Joyner } else {
4017c80429ceSEric Joyner /* If we've gotten here, then things are probably
4018c80429ceSEric Joyner * completely hosed, but if the error condition is
4019c80429ceSEric Joyner * detected, it won't hurt to give it another try...
4020c80429ceSEric Joyner * ICH_FLASH_CYCLE_REPEAT_COUNT times.
4021c80429ceSEric Joyner */
4022c80429ceSEric Joyner hsfsts.regval = E1000_READ_FLASH_REG16(hw,
4023c80429ceSEric Joyner ICH_FLASH_HSFSTS);
4024c80429ceSEric Joyner if (hsfsts.hsf_status.flcerr) {
4025c80429ceSEric Joyner /* Repeat for some time before giving up. */
4026c80429ceSEric Joyner continue;
4027c80429ceSEric Joyner } else if (!hsfsts.hsf_status.flcdone) {
4028c80429ceSEric Joyner DEBUGOUT("Timeout error - flash cycle did not complete.\n");
4029c80429ceSEric Joyner break;
4030c80429ceSEric Joyner }
4031c80429ceSEric Joyner }
4032c80429ceSEric Joyner } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
4033c80429ceSEric Joyner
4034c80429ceSEric Joyner return ret_val;
4035c80429ceSEric Joyner }
40368cc64f1eSJack F Vogel
40378cfa0ad2SJack F Vogel /**
40388cfa0ad2SJack F Vogel * e1000_write_nvm_ich8lan - Write word(s) to the NVM
40398cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
40408cfa0ad2SJack F Vogel * @offset: The offset (in bytes) of the word(s) to write.
40418cfa0ad2SJack F Vogel * @words: Size of data to write in words
40428cfa0ad2SJack F Vogel * @data: Pointer to the word(s) to write at offset.
40438cfa0ad2SJack F Vogel *
40448cfa0ad2SJack F Vogel * Writes a byte or word to the NVM using the flash access registers.
40458cfa0ad2SJack F Vogel **/
e1000_write_nvm_ich8lan(struct e1000_hw * hw,u16 offset,u16 words,u16 * data)40468cfa0ad2SJack F Vogel static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
40478cfa0ad2SJack F Vogel u16 *data)
40488cfa0ad2SJack F Vogel {
40498cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm;
4050daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
40518cfa0ad2SJack F Vogel u16 i;
40528cfa0ad2SJack F Vogel
40538cfa0ad2SJack F Vogel DEBUGFUNC("e1000_write_nvm_ich8lan");
40548cfa0ad2SJack F Vogel
40558cfa0ad2SJack F Vogel if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
40568cfa0ad2SJack F Vogel (words == 0)) {
40578cfa0ad2SJack F Vogel DEBUGOUT("nvm parameter(s) out of bounds\n");
40586ab6bfe3SJack F Vogel return -E1000_ERR_NVM;
40598cfa0ad2SJack F Vogel }
40608cfa0ad2SJack F Vogel
40614edd8523SJack F Vogel nvm->ops.acquire(hw);
40628cfa0ad2SJack F Vogel
40638cfa0ad2SJack F Vogel for (i = 0; i < words; i++) {
40641bbdc25fSKevin Bowling dev_spec->shadow_ram[offset + i].modified = true;
40658cfa0ad2SJack F Vogel dev_spec->shadow_ram[offset + i].value = data[i];
40668cfa0ad2SJack F Vogel }
40678cfa0ad2SJack F Vogel
40688cfa0ad2SJack F Vogel nvm->ops.release(hw);
40698cfa0ad2SJack F Vogel
40706ab6bfe3SJack F Vogel return E1000_SUCCESS;
40718cfa0ad2SJack F Vogel }
40728cfa0ad2SJack F Vogel
40738cfa0ad2SJack F Vogel /**
4074c80429ceSEric Joyner * e1000_update_nvm_checksum_spt - Update the checksum for NVM
4075c80429ceSEric Joyner * @hw: pointer to the HW structure
4076c80429ceSEric Joyner *
4077c80429ceSEric Joyner * The NVM checksum is updated by calling the generic update_nvm_checksum,
4078c80429ceSEric Joyner * which writes the checksum to the shadow ram. The changes in the shadow
4079c80429ceSEric Joyner * ram are then committed to the EEPROM by processing each bank at a time
4080c80429ceSEric Joyner * checking for the modified bit and writing only the pending changes.
4081c80429ceSEric Joyner * After a successful commit, the shadow ram is cleared and is ready for
4082c80429ceSEric Joyner * future writes.
4083c80429ceSEric Joyner **/
e1000_update_nvm_checksum_spt(struct e1000_hw * hw)4084c80429ceSEric Joyner static s32 e1000_update_nvm_checksum_spt(struct e1000_hw *hw)
4085c80429ceSEric Joyner {
4086c80429ceSEric Joyner struct e1000_nvm_info *nvm = &hw->nvm;
4087c80429ceSEric Joyner struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
4088c80429ceSEric Joyner u32 i, act_offset, new_bank_offset, old_bank_offset, bank;
4089c80429ceSEric Joyner s32 ret_val;
4090c80429ceSEric Joyner u32 dword = 0;
4091c80429ceSEric Joyner
4092c80429ceSEric Joyner DEBUGFUNC("e1000_update_nvm_checksum_spt");
4093c80429ceSEric Joyner
4094c80429ceSEric Joyner ret_val = e1000_update_nvm_checksum_generic(hw);
4095c80429ceSEric Joyner if (ret_val)
4096c80429ceSEric Joyner goto out;
4097c80429ceSEric Joyner
4098c80429ceSEric Joyner if (nvm->type != e1000_nvm_flash_sw)
4099c80429ceSEric Joyner goto out;
4100c80429ceSEric Joyner
4101c80429ceSEric Joyner nvm->ops.acquire(hw);
4102c80429ceSEric Joyner
4103c80429ceSEric Joyner /* We're writing to the opposite bank so if we're on bank 1,
4104c80429ceSEric Joyner * write to bank 0 etc. We also need to erase the segment that
4105c80429ceSEric Joyner * is going to be written
4106c80429ceSEric Joyner */
4107c80429ceSEric Joyner ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
4108c80429ceSEric Joyner if (ret_val != E1000_SUCCESS) {
4109c80429ceSEric Joyner DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
4110c80429ceSEric Joyner bank = 0;
4111c80429ceSEric Joyner }
4112c80429ceSEric Joyner
4113c80429ceSEric Joyner if (bank == 0) {
4114c80429ceSEric Joyner new_bank_offset = nvm->flash_bank_size;
4115c80429ceSEric Joyner old_bank_offset = 0;
4116c80429ceSEric Joyner ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
4117c80429ceSEric Joyner if (ret_val)
4118c80429ceSEric Joyner goto release;
4119c80429ceSEric Joyner } else {
4120c80429ceSEric Joyner old_bank_offset = nvm->flash_bank_size;
4121c80429ceSEric Joyner new_bank_offset = 0;
4122c80429ceSEric Joyner ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
4123c80429ceSEric Joyner if (ret_val)
4124c80429ceSEric Joyner goto release;
4125c80429ceSEric Joyner }
4126c80429ceSEric Joyner for (i = 0; i < E1000_SHADOW_RAM_WORDS; i += 2) {
4127c80429ceSEric Joyner /* Determine whether to write the value stored
4128c80429ceSEric Joyner * in the other NVM bank or a modified value stored
4129c80429ceSEric Joyner * in the shadow RAM
4130c80429ceSEric Joyner */
4131c80429ceSEric Joyner ret_val = e1000_read_flash_dword_ich8lan(hw,
4132c80429ceSEric Joyner i + old_bank_offset,
4133c80429ceSEric Joyner &dword);
4134c80429ceSEric Joyner
4135c80429ceSEric Joyner if (dev_spec->shadow_ram[i].modified) {
4136c80429ceSEric Joyner dword &= 0xffff0000;
4137c80429ceSEric Joyner dword |= (dev_spec->shadow_ram[i].value & 0xffff);
4138c80429ceSEric Joyner }
4139c80429ceSEric Joyner if (dev_spec->shadow_ram[i + 1].modified) {
4140c80429ceSEric Joyner dword &= 0x0000ffff;
4141c80429ceSEric Joyner dword |= ((dev_spec->shadow_ram[i + 1].value & 0xffff)
4142c80429ceSEric Joyner << 16);
4143c80429ceSEric Joyner }
4144c80429ceSEric Joyner if (ret_val)
4145c80429ceSEric Joyner break;
4146c80429ceSEric Joyner
4147c80429ceSEric Joyner /* If the word is 0x13, then make sure the signature bits
4148c80429ceSEric Joyner * (15:14) are 11b until the commit has completed.
4149c80429ceSEric Joyner * This will allow us to write 10b which indicates the
4150c80429ceSEric Joyner * signature is valid. We want to do this after the write
4151c80429ceSEric Joyner * has completed so that we don't mark the segment valid
4152c80429ceSEric Joyner * while the write is still in progress
4153c80429ceSEric Joyner */
4154c80429ceSEric Joyner if (i == E1000_ICH_NVM_SIG_WORD - 1)
4155c80429ceSEric Joyner dword |= E1000_ICH_NVM_SIG_MASK << 16;
4156c80429ceSEric Joyner
4157c80429ceSEric Joyner /* Convert offset to bytes. */
4158c80429ceSEric Joyner act_offset = (i + new_bank_offset) << 1;
4159c80429ceSEric Joyner
4160c80429ceSEric Joyner usec_delay(100);
4161c80429ceSEric Joyner
4162c80429ceSEric Joyner /* Write the data to the new bank. Offset in words*/
4163c80429ceSEric Joyner act_offset = i + new_bank_offset;
4164c80429ceSEric Joyner ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset,
4165c80429ceSEric Joyner dword);
4166c80429ceSEric Joyner if (ret_val)
4167c80429ceSEric Joyner break;
4168c80429ceSEric Joyner }
4169c80429ceSEric Joyner
4170c80429ceSEric Joyner /* Don't bother writing the segment valid bits if sector
4171c80429ceSEric Joyner * programming failed.
4172c80429ceSEric Joyner */
4173c80429ceSEric Joyner if (ret_val) {
4174c80429ceSEric Joyner DEBUGOUT("Flash commit failed.\n");
4175c80429ceSEric Joyner goto release;
4176c80429ceSEric Joyner }
4177c80429ceSEric Joyner
4178c80429ceSEric Joyner /* Finally validate the new segment by setting bit 15:14
4179c80429ceSEric Joyner * to 10b in word 0x13 , this can be done without an
4180c80429ceSEric Joyner * erase as well since these bits are 11 to start with
4181c80429ceSEric Joyner * and we need to change bit 14 to 0b
4182c80429ceSEric Joyner */
4183c80429ceSEric Joyner act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
4184c80429ceSEric Joyner
4185c80429ceSEric Joyner /*offset in words but we read dword*/
4186c80429ceSEric Joyner --act_offset;
4187c80429ceSEric Joyner ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset, &dword);
4188c80429ceSEric Joyner
4189c80429ceSEric Joyner if (ret_val)
4190c80429ceSEric Joyner goto release;
4191c80429ceSEric Joyner
4192c80429ceSEric Joyner dword &= 0xBFFFFFFF;
4193c80429ceSEric Joyner ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset, dword);
4194c80429ceSEric Joyner
4195c80429ceSEric Joyner if (ret_val)
4196c80429ceSEric Joyner goto release;
4197c80429ceSEric Joyner
4198c80429ceSEric Joyner /* offset in words but we read dword*/
4199c80429ceSEric Joyner act_offset = old_bank_offset + E1000_ICH_NVM_SIG_WORD - 1;
4200c80429ceSEric Joyner ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset, &dword);
4201c80429ceSEric Joyner
4202c80429ceSEric Joyner if (ret_val)
4203c80429ceSEric Joyner goto release;
4204c80429ceSEric Joyner
4205c80429ceSEric Joyner dword &= 0x00FFFFFF;
4206c80429ceSEric Joyner ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset, dword);
4207c80429ceSEric Joyner
4208c80429ceSEric Joyner if (ret_val)
4209c80429ceSEric Joyner goto release;
4210c80429ceSEric Joyner
4211c80429ceSEric Joyner /* Great! Everything worked, we can now clear the cached entries. */
4212c80429ceSEric Joyner for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
42131bbdc25fSKevin Bowling dev_spec->shadow_ram[i].modified = false;
4214c80429ceSEric Joyner dev_spec->shadow_ram[i].value = 0xFFFF;
4215c80429ceSEric Joyner }
4216c80429ceSEric Joyner
4217c80429ceSEric Joyner release:
4218c80429ceSEric Joyner nvm->ops.release(hw);
4219c80429ceSEric Joyner
4220c80429ceSEric Joyner /* Reload the EEPROM, or else modifications will not appear
4221c80429ceSEric Joyner * until after the next adapter reset.
4222c80429ceSEric Joyner */
4223c80429ceSEric Joyner if (!ret_val) {
4224c80429ceSEric Joyner nvm->ops.reload(hw);
4225c80429ceSEric Joyner msec_delay(10);
4226c80429ceSEric Joyner }
4227c80429ceSEric Joyner
4228c80429ceSEric Joyner out:
4229c80429ceSEric Joyner if (ret_val)
4230c80429ceSEric Joyner DEBUGOUT1("NVM update error: %d\n", ret_val);
4231c80429ceSEric Joyner
4232c80429ceSEric Joyner return ret_val;
4233c80429ceSEric Joyner }
4234c80429ceSEric Joyner
4235c80429ceSEric Joyner /**
42368cfa0ad2SJack F Vogel * e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM
42378cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
42388cfa0ad2SJack F Vogel *
42398cfa0ad2SJack F Vogel * The NVM checksum is updated by calling the generic update_nvm_checksum,
42408cfa0ad2SJack F Vogel * which writes the checksum to the shadow ram. The changes in the shadow
42418cfa0ad2SJack F Vogel * ram are then committed to the EEPROM by processing each bank at a time
42428cfa0ad2SJack F Vogel * checking for the modified bit and writing only the pending changes.
42438cfa0ad2SJack F Vogel * After a successful commit, the shadow ram is cleared and is ready for
42448cfa0ad2SJack F Vogel * future writes.
42458cfa0ad2SJack F Vogel **/
e1000_update_nvm_checksum_ich8lan(struct e1000_hw * hw)42468cfa0ad2SJack F Vogel static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
42478cfa0ad2SJack F Vogel {
42488cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm;
4249daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
42508cfa0ad2SJack F Vogel u32 i, act_offset, new_bank_offset, old_bank_offset, bank;
42518cfa0ad2SJack F Vogel s32 ret_val;
42528cc64f1eSJack F Vogel u16 data = 0;
42538cfa0ad2SJack F Vogel
42548cfa0ad2SJack F Vogel DEBUGFUNC("e1000_update_nvm_checksum_ich8lan");
42558cfa0ad2SJack F Vogel
42568cfa0ad2SJack F Vogel ret_val = e1000_update_nvm_checksum_generic(hw);
42578cfa0ad2SJack F Vogel if (ret_val)
42588cfa0ad2SJack F Vogel goto out;
42598cfa0ad2SJack F Vogel
42608cfa0ad2SJack F Vogel if (nvm->type != e1000_nvm_flash_sw)
42618cfa0ad2SJack F Vogel goto out;
42628cfa0ad2SJack F Vogel
42634edd8523SJack F Vogel nvm->ops.acquire(hw);
42648cfa0ad2SJack F Vogel
42656ab6bfe3SJack F Vogel /* We're writing to the opposite bank so if we're on bank 1,
42668cfa0ad2SJack F Vogel * write to bank 0 etc. We also need to erase the segment that
42678cfa0ad2SJack F Vogel * is going to be written
42688cfa0ad2SJack F Vogel */
42698cfa0ad2SJack F Vogel ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
4270d035aa2dSJack F Vogel if (ret_val != E1000_SUCCESS) {
42714edd8523SJack F Vogel DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
42724edd8523SJack F Vogel bank = 0;
4273d035aa2dSJack F Vogel }
42748cfa0ad2SJack F Vogel
42758cfa0ad2SJack F Vogel if (bank == 0) {
42768cfa0ad2SJack F Vogel new_bank_offset = nvm->flash_bank_size;
42778cfa0ad2SJack F Vogel old_bank_offset = 0;
4278d035aa2dSJack F Vogel ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
4279a69ed8dfSJack F Vogel if (ret_val)
4280a69ed8dfSJack F Vogel goto release;
42818cfa0ad2SJack F Vogel } else {
42828cfa0ad2SJack F Vogel old_bank_offset = nvm->flash_bank_size;
42838cfa0ad2SJack F Vogel new_bank_offset = 0;
4284d035aa2dSJack F Vogel ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
4285a69ed8dfSJack F Vogel if (ret_val)
4286a69ed8dfSJack F Vogel goto release;
42878cfa0ad2SJack F Vogel }
42888cfa0ad2SJack F Vogel for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
42898cfa0ad2SJack F Vogel if (dev_spec->shadow_ram[i].modified) {
42908cfa0ad2SJack F Vogel data = dev_spec->shadow_ram[i].value;
42918cfa0ad2SJack F Vogel } else {
4292d035aa2dSJack F Vogel ret_val = e1000_read_flash_word_ich8lan(hw, i +
4293d035aa2dSJack F Vogel old_bank_offset,
42948cfa0ad2SJack F Vogel &data);
4295d035aa2dSJack F Vogel if (ret_val)
4296d035aa2dSJack F Vogel break;
42978cfa0ad2SJack F Vogel }
42986ab6bfe3SJack F Vogel /* If the word is 0x13, then make sure the signature bits
42998cfa0ad2SJack F Vogel * (15:14) are 11b until the commit has completed.
43008cfa0ad2SJack F Vogel * This will allow us to write 10b which indicates the
43018cfa0ad2SJack F Vogel * signature is valid. We want to do this after the write
43028cfa0ad2SJack F Vogel * has completed so that we don't mark the segment valid
43038cfa0ad2SJack F Vogel * while the write is still in progress
43048cfa0ad2SJack F Vogel */
43058cfa0ad2SJack F Vogel if (i == E1000_ICH_NVM_SIG_WORD)
43068cfa0ad2SJack F Vogel data |= E1000_ICH_NVM_SIG_MASK;
43078cfa0ad2SJack F Vogel
43088cfa0ad2SJack F Vogel /* Convert offset to bytes. */
43098cfa0ad2SJack F Vogel act_offset = (i + new_bank_offset) << 1;
43108cfa0ad2SJack F Vogel
43118cfa0ad2SJack F Vogel usec_delay(100);
43128cc64f1eSJack F Vogel
43138cfa0ad2SJack F Vogel /* Write the bytes to the new bank. */
43148cfa0ad2SJack F Vogel ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
43158cfa0ad2SJack F Vogel act_offset,
43168cfa0ad2SJack F Vogel (u8)data);
43178cfa0ad2SJack F Vogel if (ret_val)
43188cfa0ad2SJack F Vogel break;
43198cfa0ad2SJack F Vogel
43208cfa0ad2SJack F Vogel usec_delay(100);
43218cfa0ad2SJack F Vogel ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
43228cfa0ad2SJack F Vogel act_offset + 1,
43238cfa0ad2SJack F Vogel (u8)(data >> 8));
43248cfa0ad2SJack F Vogel if (ret_val)
43258cfa0ad2SJack F Vogel break;
43268cfa0ad2SJack F Vogel }
43278cfa0ad2SJack F Vogel
43286ab6bfe3SJack F Vogel /* Don't bother writing the segment valid bits if sector
43298cfa0ad2SJack F Vogel * programming failed.
43308cfa0ad2SJack F Vogel */
43318cfa0ad2SJack F Vogel if (ret_val) {
43328cfa0ad2SJack F Vogel DEBUGOUT("Flash commit failed.\n");
4333a69ed8dfSJack F Vogel goto release;
43348cfa0ad2SJack F Vogel }
43358cfa0ad2SJack F Vogel
43366ab6bfe3SJack F Vogel /* Finally validate the new segment by setting bit 15:14
43378cfa0ad2SJack F Vogel * to 10b in word 0x13 , this can be done without an
43388cfa0ad2SJack F Vogel * erase as well since these bits are 11 to start with
43398cfa0ad2SJack F Vogel * and we need to change bit 14 to 0b
43408cfa0ad2SJack F Vogel */
43418cfa0ad2SJack F Vogel act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
4342d035aa2dSJack F Vogel ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data);
4343a69ed8dfSJack F Vogel if (ret_val)
4344a69ed8dfSJack F Vogel goto release;
43454edd8523SJack F Vogel
43468cfa0ad2SJack F Vogel data &= 0xBFFF;
43478cc64f1eSJack F Vogel ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset * 2 + 1,
43488cfa0ad2SJack F Vogel (u8)(data >> 8));
4349a69ed8dfSJack F Vogel if (ret_val)
4350a69ed8dfSJack F Vogel goto release;
43518cfa0ad2SJack F Vogel
43526ab6bfe3SJack F Vogel /* And invalidate the previously valid segment by setting
43538cfa0ad2SJack F Vogel * its signature word (0x13) high_byte to 0b. This can be
43548cfa0ad2SJack F Vogel * done without an erase because flash erase sets all bits
43558cfa0ad2SJack F Vogel * to 1's. We can write 1's to 0's without an erase
43568cfa0ad2SJack F Vogel */
43578cfa0ad2SJack F Vogel act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
43588cc64f1eSJack F Vogel
43598cfa0ad2SJack F Vogel ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
43608cc64f1eSJack F Vogel
4361a69ed8dfSJack F Vogel if (ret_val)
4362a69ed8dfSJack F Vogel goto release;
43638cfa0ad2SJack F Vogel
43648cfa0ad2SJack F Vogel /* Great! Everything worked, we can now clear the cached entries. */
43658cfa0ad2SJack F Vogel for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
43661bbdc25fSKevin Bowling dev_spec->shadow_ram[i].modified = false;
43678cfa0ad2SJack F Vogel dev_spec->shadow_ram[i].value = 0xFFFF;
43688cfa0ad2SJack F Vogel }
43698cfa0ad2SJack F Vogel
4370a69ed8dfSJack F Vogel release:
43718cfa0ad2SJack F Vogel nvm->ops.release(hw);
43728cfa0ad2SJack F Vogel
43736ab6bfe3SJack F Vogel /* Reload the EEPROM, or else modifications will not appear
43748cfa0ad2SJack F Vogel * until after the next adapter reset.
43758cfa0ad2SJack F Vogel */
4376a69ed8dfSJack F Vogel if (!ret_val) {
43778cfa0ad2SJack F Vogel nvm->ops.reload(hw);
43788cfa0ad2SJack F Vogel msec_delay(10);
4379a69ed8dfSJack F Vogel }
43808cfa0ad2SJack F Vogel
43818cfa0ad2SJack F Vogel out:
4382d035aa2dSJack F Vogel if (ret_val)
4383d035aa2dSJack F Vogel DEBUGOUT1("NVM update error: %d\n", ret_val);
4384d035aa2dSJack F Vogel
43858cfa0ad2SJack F Vogel return ret_val;
43868cfa0ad2SJack F Vogel }
43878cfa0ad2SJack F Vogel
43888cfa0ad2SJack F Vogel /**
43898cfa0ad2SJack F Vogel * e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum
43908cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
43918cfa0ad2SJack F Vogel *
43928cfa0ad2SJack F Vogel * Check to see if checksum needs to be fixed by reading bit 6 in word 0x19.
4393daf9197cSJack F Vogel * If the bit is 0, that the EEPROM had been modified, but the checksum was not
4394daf9197cSJack F Vogel * calculated, in which case we need to calculate the checksum and set bit 6.
43958cfa0ad2SJack F Vogel **/
e1000_validate_nvm_checksum_ich8lan(struct e1000_hw * hw)43968cfa0ad2SJack F Vogel static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
43978cfa0ad2SJack F Vogel {
43986ab6bfe3SJack F Vogel s32 ret_val;
43998cfa0ad2SJack F Vogel u16 data;
44006ab6bfe3SJack F Vogel u16 word;
44016ab6bfe3SJack F Vogel u16 valid_csum_mask;
44028cfa0ad2SJack F Vogel
44038cfa0ad2SJack F Vogel DEBUGFUNC("e1000_validate_nvm_checksum_ich8lan");
44048cfa0ad2SJack F Vogel
44056ab6bfe3SJack F Vogel /* Read NVM and check Invalid Image CSUM bit. If this bit is 0,
44066ab6bfe3SJack F Vogel * the checksum needs to be fixed. This bit is an indication that
44076ab6bfe3SJack F Vogel * the NVM was prepared by OEM software and did not calculate
44086ab6bfe3SJack F Vogel * the checksum...a likely scenario.
44098cfa0ad2SJack F Vogel */
44106ab6bfe3SJack F Vogel switch (hw->mac.type) {
44116ab6bfe3SJack F Vogel case e1000_pch_lpt:
4412c80429ceSEric Joyner case e1000_pch_spt:
44136fe4c0a0SSean Bruno case e1000_pch_cnp:
441459690eabSKevin Bowling case e1000_pch_tgp:
441559690eabSKevin Bowling case e1000_pch_adp:
441659690eabSKevin Bowling case e1000_pch_mtp:
4417*905ae588SKevin Bowling case e1000_pch_ptp:
44186ab6bfe3SJack F Vogel word = NVM_COMPAT;
44196ab6bfe3SJack F Vogel valid_csum_mask = NVM_COMPAT_VALID_CSUM;
44206ab6bfe3SJack F Vogel break;
44216ab6bfe3SJack F Vogel default:
44226ab6bfe3SJack F Vogel word = NVM_FUTURE_INIT_WORD1;
44236ab6bfe3SJack F Vogel valid_csum_mask = NVM_FUTURE_INIT_WORD1_VALID_CSUM;
44246ab6bfe3SJack F Vogel break;
44258cfa0ad2SJack F Vogel }
44268cfa0ad2SJack F Vogel
44276ab6bfe3SJack F Vogel ret_val = hw->nvm.ops.read(hw, word, 1, &data);
44286ab6bfe3SJack F Vogel if (ret_val)
44298cfa0ad2SJack F Vogel return ret_val;
44306ab6bfe3SJack F Vogel
44316ab6bfe3SJack F Vogel if (!(data & valid_csum_mask)) {
44326ab6bfe3SJack F Vogel data |= valid_csum_mask;
44336ab6bfe3SJack F Vogel ret_val = hw->nvm.ops.write(hw, word, 1, &data);
44346ab6bfe3SJack F Vogel if (ret_val)
44356ab6bfe3SJack F Vogel return ret_val;
44366ab6bfe3SJack F Vogel ret_val = hw->nvm.ops.update(hw);
44376ab6bfe3SJack F Vogel if (ret_val)
44386ab6bfe3SJack F Vogel return ret_val;
44396ab6bfe3SJack F Vogel }
44406ab6bfe3SJack F Vogel
44416ab6bfe3SJack F Vogel return e1000_validate_nvm_checksum_generic(hw);
44428cfa0ad2SJack F Vogel }
44438cfa0ad2SJack F Vogel
44448cfa0ad2SJack F Vogel /**
44458cfa0ad2SJack F Vogel * e1000_write_flash_data_ich8lan - Writes bytes to the NVM
44468cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
44478cfa0ad2SJack F Vogel * @offset: The offset (in bytes) of the byte/word to read.
44488cfa0ad2SJack F Vogel * @size: Size of data to read, 1=byte 2=word
44498cfa0ad2SJack F Vogel * @data: The byte(s) to write to the NVM.
44508cfa0ad2SJack F Vogel *
44518cfa0ad2SJack F Vogel * Writes one/two bytes to the NVM using the flash access registers.
44528cfa0ad2SJack F Vogel **/
e1000_write_flash_data_ich8lan(struct e1000_hw * hw,u32 offset,u8 size,u16 data)44538cfa0ad2SJack F Vogel static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
44548cfa0ad2SJack F Vogel u8 size, u16 data)
44558cfa0ad2SJack F Vogel {
44568cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts;
44578cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl hsflctl;
44588cfa0ad2SJack F Vogel u32 flash_linear_addr;
44598cfa0ad2SJack F Vogel u32 flash_data = 0;
44606ab6bfe3SJack F Vogel s32 ret_val;
44618cfa0ad2SJack F Vogel u8 count = 0;
44628cfa0ad2SJack F Vogel
44638cfa0ad2SJack F Vogel DEBUGFUNC("e1000_write_ich8_data");
44648cfa0ad2SJack F Vogel
4465295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt) {
4466c80429ceSEric Joyner if (size != 4 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
4467c80429ceSEric Joyner return -E1000_ERR_NVM;
4468c80429ceSEric Joyner } else {
44698cc64f1eSJack F Vogel if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
44706ab6bfe3SJack F Vogel return -E1000_ERR_NVM;
4471c80429ceSEric Joyner }
44728cfa0ad2SJack F Vogel
44737609433eSJack F Vogel flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
44747609433eSJack F Vogel hw->nvm.flash_base_addr);
44758cfa0ad2SJack F Vogel
44768cfa0ad2SJack F Vogel do {
44778cfa0ad2SJack F Vogel usec_delay(1);
44788cfa0ad2SJack F Vogel /* Steps */
44798cfa0ad2SJack F Vogel ret_val = e1000_flash_cycle_init_ich8lan(hw);
44808cfa0ad2SJack F Vogel if (ret_val != E1000_SUCCESS)
44818cfa0ad2SJack F Vogel break;
4482c80429ceSEric Joyner /* In SPT, This register is in Lan memory space, not
4483c80429ceSEric Joyner * flash. Therefore, only 32 bit access is supported
4484c80429ceSEric Joyner */
4485295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt)
4486c80429ceSEric Joyner hsflctl.regval =
4487c80429ceSEric Joyner E1000_READ_FLASH_REG(hw, ICH_FLASH_HSFSTS)>>16;
4488c80429ceSEric Joyner else
4489c80429ceSEric Joyner hsflctl.regval =
4490c80429ceSEric Joyner E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
44918cc64f1eSJack F Vogel
44928cfa0ad2SJack F Vogel /* 0b/1b corresponds to 1 or 2 byte size, respectively. */
44938cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.fldbcount = size - 1;
44948cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
4495c80429ceSEric Joyner /* In SPT, This register is in Lan memory space,
4496c80429ceSEric Joyner * not flash. Therefore, only 32 bit access is
4497c80429ceSEric Joyner * supported
4498c80429ceSEric Joyner */
4499295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt)
4500c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
4501c80429ceSEric Joyner hsflctl.regval << 16);
4502c80429ceSEric Joyner else
4503c80429ceSEric Joyner E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL,
4504c80429ceSEric Joyner hsflctl.regval);
45058cfa0ad2SJack F Vogel
45068cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
45078cfa0ad2SJack F Vogel
45088cfa0ad2SJack F Vogel if (size == 1)
45098cfa0ad2SJack F Vogel flash_data = (u32)data & 0x00FF;
45108cfa0ad2SJack F Vogel else
45118cfa0ad2SJack F Vogel flash_data = (u32)data;
45128cfa0ad2SJack F Vogel
45138cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, flash_data);
45148cfa0ad2SJack F Vogel
45156ab6bfe3SJack F Vogel /* check if FCERR is set to 1 , if set to 1, clear it
45168cfa0ad2SJack F Vogel * and try the whole sequence a few more times else done
45178cfa0ad2SJack F Vogel */
45187609433eSJack F Vogel ret_val =
45197609433eSJack F Vogel e1000_flash_cycle_ich8lan(hw,
45208cfa0ad2SJack F Vogel ICH_FLASH_WRITE_COMMAND_TIMEOUT);
4521daf9197cSJack F Vogel if (ret_val == E1000_SUCCESS)
45228cfa0ad2SJack F Vogel break;
4523daf9197cSJack F Vogel
45246ab6bfe3SJack F Vogel /* If we're here, then things are most likely
45258cfa0ad2SJack F Vogel * completely hosed, but if the error condition
45268cfa0ad2SJack F Vogel * is detected, it won't hurt to give it another
45278cfa0ad2SJack F Vogel * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
45288cfa0ad2SJack F Vogel */
4529daf9197cSJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
45306ab6bfe3SJack F Vogel if (hsfsts.hsf_status.flcerr)
45318cfa0ad2SJack F Vogel /* Repeat for some time before giving up. */
45328cfa0ad2SJack F Vogel continue;
45336ab6bfe3SJack F Vogel if (!hsfsts.hsf_status.flcdone) {
45344dab5c37SJack F Vogel DEBUGOUT("Timeout error - flash cycle did not complete.\n");
45358cfa0ad2SJack F Vogel break;
45368cfa0ad2SJack F Vogel }
45378cfa0ad2SJack F Vogel } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
45388cfa0ad2SJack F Vogel
45398cfa0ad2SJack F Vogel return ret_val;
45408cfa0ad2SJack F Vogel }
45418cfa0ad2SJack F Vogel
4542c80429ceSEric Joyner /**
4543c80429ceSEric Joyner * e1000_write_flash_data32_ich8lan - Writes 4 bytes to the NVM
4544c80429ceSEric Joyner * @hw: pointer to the HW structure
4545c80429ceSEric Joyner * @offset: The offset (in bytes) of the dwords to read.
4546c80429ceSEric Joyner * @data: The 4 bytes to write to the NVM.
4547c80429ceSEric Joyner *
4548c80429ceSEric Joyner * Writes one/two/four bytes to the NVM using the flash access registers.
4549c80429ceSEric Joyner **/
e1000_write_flash_data32_ich8lan(struct e1000_hw * hw,u32 offset,u32 data)4550c80429ceSEric Joyner static s32 e1000_write_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset,
4551c80429ceSEric Joyner u32 data)
4552c80429ceSEric Joyner {
4553c80429ceSEric Joyner union ich8_hws_flash_status hsfsts;
4554c80429ceSEric Joyner union ich8_hws_flash_ctrl hsflctl;
4555c80429ceSEric Joyner u32 flash_linear_addr;
4556c80429ceSEric Joyner s32 ret_val;
4557c80429ceSEric Joyner u8 count = 0;
4558c80429ceSEric Joyner
4559c80429ceSEric Joyner DEBUGFUNC("e1000_write_flash_data32_ich8lan");
4560c80429ceSEric Joyner
4561295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt) {
4562c80429ceSEric Joyner if (offset > ICH_FLASH_LINEAR_ADDR_MASK)
4563c80429ceSEric Joyner return -E1000_ERR_NVM;
4564c80429ceSEric Joyner }
4565c80429ceSEric Joyner flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
4566c80429ceSEric Joyner hw->nvm.flash_base_addr);
4567c80429ceSEric Joyner do {
4568c80429ceSEric Joyner usec_delay(1);
4569c80429ceSEric Joyner /* Steps */
4570c80429ceSEric Joyner ret_val = e1000_flash_cycle_init_ich8lan(hw);
4571c80429ceSEric Joyner if (ret_val != E1000_SUCCESS)
4572c80429ceSEric Joyner break;
4573c80429ceSEric Joyner
4574c80429ceSEric Joyner /* In SPT, This register is in Lan memory space, not
4575c80429ceSEric Joyner * flash. Therefore, only 32 bit access is supported
4576c80429ceSEric Joyner */
4577295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt)
4578c80429ceSEric Joyner hsflctl.regval = E1000_READ_FLASH_REG(hw,
4579c80429ceSEric Joyner ICH_FLASH_HSFSTS)
4580c80429ceSEric Joyner >> 16;
4581c80429ceSEric Joyner else
4582c80429ceSEric Joyner hsflctl.regval = E1000_READ_FLASH_REG16(hw,
4583c80429ceSEric Joyner ICH_FLASH_HSFCTL);
4584c80429ceSEric Joyner
4585c80429ceSEric Joyner hsflctl.hsf_ctrl.fldbcount = sizeof(u32) - 1;
4586c80429ceSEric Joyner hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
4587c80429ceSEric Joyner
4588c80429ceSEric Joyner /* In SPT, This register is in Lan memory space,
4589c80429ceSEric Joyner * not flash. Therefore, only 32 bit access is
4590c80429ceSEric Joyner * supported
4591c80429ceSEric Joyner */
4592295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt)
4593c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
4594c80429ceSEric Joyner hsflctl.regval << 16);
4595c80429ceSEric Joyner else
4596c80429ceSEric Joyner E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL,
4597c80429ceSEric Joyner hsflctl.regval);
4598c80429ceSEric Joyner
4599c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
4600c80429ceSEric Joyner
4601c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, data);
4602c80429ceSEric Joyner
4603c80429ceSEric Joyner /* check if FCERR is set to 1 , if set to 1, clear it
4604c80429ceSEric Joyner * and try the whole sequence a few more times else done
4605c80429ceSEric Joyner */
4606c80429ceSEric Joyner ret_val = e1000_flash_cycle_ich8lan(hw,
4607c80429ceSEric Joyner ICH_FLASH_WRITE_COMMAND_TIMEOUT);
4608c80429ceSEric Joyner
4609c80429ceSEric Joyner if (ret_val == E1000_SUCCESS)
4610c80429ceSEric Joyner break;
4611c80429ceSEric Joyner
4612c80429ceSEric Joyner /* If we're here, then things are most likely
4613c80429ceSEric Joyner * completely hosed, but if the error condition
4614c80429ceSEric Joyner * is detected, it won't hurt to give it another
4615c80429ceSEric Joyner * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
4616c80429ceSEric Joyner */
4617c80429ceSEric Joyner hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
4618c80429ceSEric Joyner
4619c80429ceSEric Joyner if (hsfsts.hsf_status.flcerr)
4620c80429ceSEric Joyner /* Repeat for some time before giving up. */
4621c80429ceSEric Joyner continue;
4622c80429ceSEric Joyner if (!hsfsts.hsf_status.flcdone) {
4623c80429ceSEric Joyner DEBUGOUT("Timeout error - flash cycle did not complete.\n");
4624c80429ceSEric Joyner break;
4625c80429ceSEric Joyner }
4626c80429ceSEric Joyner } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
4627c80429ceSEric Joyner
4628c80429ceSEric Joyner return ret_val;
4629c80429ceSEric Joyner }
46308cc64f1eSJack F Vogel
46318cfa0ad2SJack F Vogel /**
46328cfa0ad2SJack F Vogel * e1000_write_flash_byte_ich8lan - Write a single byte to NVM
46338cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
46348cfa0ad2SJack F Vogel * @offset: The index of the byte to read.
46358cfa0ad2SJack F Vogel * @data: The byte to write to the NVM.
46368cfa0ad2SJack F Vogel *
46378cfa0ad2SJack F Vogel * Writes a single byte to the NVM using the flash access registers.
46388cfa0ad2SJack F Vogel **/
e1000_write_flash_byte_ich8lan(struct e1000_hw * hw,u32 offset,u8 data)46398cfa0ad2SJack F Vogel static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
46408cfa0ad2SJack F Vogel u8 data)
46418cfa0ad2SJack F Vogel {
46428cfa0ad2SJack F Vogel u16 word = (u16)data;
46438cfa0ad2SJack F Vogel
46448cfa0ad2SJack F Vogel DEBUGFUNC("e1000_write_flash_byte_ich8lan");
46458cfa0ad2SJack F Vogel
46468cfa0ad2SJack F Vogel return e1000_write_flash_data_ich8lan(hw, offset, 1, word);
46478cfa0ad2SJack F Vogel }
46488cfa0ad2SJack F Vogel
4649c80429ceSEric Joyner /**
4650c80429ceSEric Joyner * e1000_retry_write_flash_dword_ich8lan - Writes a dword to NVM
4651c80429ceSEric Joyner * @hw: pointer to the HW structure
4652c80429ceSEric Joyner * @offset: The offset of the word to write.
4653c80429ceSEric Joyner * @dword: The dword to write to the NVM.
4654c80429ceSEric Joyner *
4655c80429ceSEric Joyner * Writes a single dword to the NVM using the flash access registers.
4656c80429ceSEric Joyner * Goes through a retry algorithm before giving up.
4657c80429ceSEric Joyner **/
e1000_retry_write_flash_dword_ich8lan(struct e1000_hw * hw,u32 offset,u32 dword)4658c80429ceSEric Joyner static s32 e1000_retry_write_flash_dword_ich8lan(struct e1000_hw *hw,
4659c80429ceSEric Joyner u32 offset, u32 dword)
4660c80429ceSEric Joyner {
4661c80429ceSEric Joyner s32 ret_val;
4662c80429ceSEric Joyner u16 program_retries;
46638cc64f1eSJack F Vogel
4664c80429ceSEric Joyner DEBUGFUNC("e1000_retry_write_flash_dword_ich8lan");
4665c80429ceSEric Joyner
4666c80429ceSEric Joyner /* Must convert word offset into bytes. */
4667c80429ceSEric Joyner offset <<= 1;
4668c80429ceSEric Joyner
4669c80429ceSEric Joyner ret_val = e1000_write_flash_data32_ich8lan(hw, offset, dword);
4670c80429ceSEric Joyner
4671c80429ceSEric Joyner if (!ret_val)
4672c80429ceSEric Joyner return ret_val;
4673c80429ceSEric Joyner for (program_retries = 0; program_retries < 100; program_retries++) {
4674c80429ceSEric Joyner DEBUGOUT2("Retrying Byte %8.8X at offset %u\n", dword, offset);
4675c80429ceSEric Joyner usec_delay(100);
4676c80429ceSEric Joyner ret_val = e1000_write_flash_data32_ich8lan(hw, offset, dword);
4677c80429ceSEric Joyner if (ret_val == E1000_SUCCESS)
4678c80429ceSEric Joyner break;
4679c80429ceSEric Joyner }
4680c80429ceSEric Joyner if (program_retries == 100)
4681c80429ceSEric Joyner return -E1000_ERR_NVM;
4682c80429ceSEric Joyner
4683c80429ceSEric Joyner return E1000_SUCCESS;
4684c80429ceSEric Joyner }
46858cc64f1eSJack F Vogel
46868cfa0ad2SJack F Vogel /**
46878cfa0ad2SJack F Vogel * e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM
46888cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
46898cfa0ad2SJack F Vogel * @offset: The offset of the byte to write.
46908cfa0ad2SJack F Vogel * @byte: The byte to write to the NVM.
46918cfa0ad2SJack F Vogel *
46928cfa0ad2SJack F Vogel * Writes a single byte to the NVM using the flash access registers.
46938cfa0ad2SJack F Vogel * Goes through a retry algorithm before giving up.
46948cfa0ad2SJack F Vogel **/
e1000_retry_write_flash_byte_ich8lan(struct e1000_hw * hw,u32 offset,u8 byte)46958cfa0ad2SJack F Vogel static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
46968cfa0ad2SJack F Vogel u32 offset, u8 byte)
46978cfa0ad2SJack F Vogel {
46988cfa0ad2SJack F Vogel s32 ret_val;
46998cfa0ad2SJack F Vogel u16 program_retries;
47008cfa0ad2SJack F Vogel
47018cfa0ad2SJack F Vogel DEBUGFUNC("e1000_retry_write_flash_byte_ich8lan");
47028cfa0ad2SJack F Vogel
47038cfa0ad2SJack F Vogel ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
47046ab6bfe3SJack F Vogel if (!ret_val)
47056ab6bfe3SJack F Vogel return ret_val;
47068cfa0ad2SJack F Vogel
47078cfa0ad2SJack F Vogel for (program_retries = 0; program_retries < 100; program_retries++) {
47088cfa0ad2SJack F Vogel DEBUGOUT2("Retrying Byte %2.2X at offset %u\n", byte, offset);
47098cfa0ad2SJack F Vogel usec_delay(100);
47108cfa0ad2SJack F Vogel ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
47118cfa0ad2SJack F Vogel if (ret_val == E1000_SUCCESS)
47128cfa0ad2SJack F Vogel break;
47138cfa0ad2SJack F Vogel }
47146ab6bfe3SJack F Vogel if (program_retries == 100)
47156ab6bfe3SJack F Vogel return -E1000_ERR_NVM;
47168cfa0ad2SJack F Vogel
47176ab6bfe3SJack F Vogel return E1000_SUCCESS;
47188cfa0ad2SJack F Vogel }
47198cfa0ad2SJack F Vogel
47208cfa0ad2SJack F Vogel /**
47218cfa0ad2SJack F Vogel * e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM
47228cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
47238cfa0ad2SJack F Vogel * @bank: 0 for first bank, 1 for second bank, etc.
47248cfa0ad2SJack F Vogel *
47258cfa0ad2SJack F Vogel * Erases the bank specified. Each bank is a 4k block. Banks are 0 based.
47268cfa0ad2SJack F Vogel * bank N is 4096 * N + flash_reg_addr.
47278cfa0ad2SJack F Vogel **/
e1000_erase_flash_bank_ich8lan(struct e1000_hw * hw,u32 bank)47288cfa0ad2SJack F Vogel static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
47298cfa0ad2SJack F Vogel {
47308cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm;
47318cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts;
47328cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl hsflctl;
47338cfa0ad2SJack F Vogel u32 flash_linear_addr;
47348cfa0ad2SJack F Vogel /* bank size is in 16bit words - adjust to bytes */
47358cfa0ad2SJack F Vogel u32 flash_bank_size = nvm->flash_bank_size * 2;
47366ab6bfe3SJack F Vogel s32 ret_val;
47378cfa0ad2SJack F Vogel s32 count = 0;
47388cfa0ad2SJack F Vogel s32 j, iteration, sector_size;
47398cfa0ad2SJack F Vogel
47408cfa0ad2SJack F Vogel DEBUGFUNC("e1000_erase_flash_bank_ich8lan");
47418cfa0ad2SJack F Vogel
47428cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
47438cfa0ad2SJack F Vogel
47446ab6bfe3SJack F Vogel /* Determine HW Sector size: Read BERASE bits of hw flash status
47458cfa0ad2SJack F Vogel * register
47468cfa0ad2SJack F Vogel * 00: The Hw sector is 256 bytes, hence we need to erase 16
47478cfa0ad2SJack F Vogel * consecutive sectors. The start index for the nth Hw sector
47488cfa0ad2SJack F Vogel * can be calculated as = bank * 4096 + n * 256
47498cfa0ad2SJack F Vogel * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
47508cfa0ad2SJack F Vogel * The start index for the nth Hw sector can be calculated
47518cfa0ad2SJack F Vogel * as = bank * 4096
47528cfa0ad2SJack F Vogel * 10: The Hw sector is 8K bytes, nth sector = bank * 8192
47538cfa0ad2SJack F Vogel * (ich9 only, otherwise error condition)
47548cfa0ad2SJack F Vogel * 11: The Hw sector is 64K bytes, nth sector = bank * 65536
47558cfa0ad2SJack F Vogel */
47568cfa0ad2SJack F Vogel switch (hsfsts.hsf_status.berasesz) {
47578cfa0ad2SJack F Vogel case 0:
47588cfa0ad2SJack F Vogel /* Hw sector size 256 */
47598cfa0ad2SJack F Vogel sector_size = ICH_FLASH_SEG_SIZE_256;
47608cfa0ad2SJack F Vogel iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256;
47618cfa0ad2SJack F Vogel break;
47628cfa0ad2SJack F Vogel case 1:
47638cfa0ad2SJack F Vogel sector_size = ICH_FLASH_SEG_SIZE_4K;
47649d81738fSJack F Vogel iteration = 1;
47658cfa0ad2SJack F Vogel break;
47668cfa0ad2SJack F Vogel case 2:
47678cfa0ad2SJack F Vogel sector_size = ICH_FLASH_SEG_SIZE_8K;
47688bd0025fSJack F Vogel iteration = 1;
47698cfa0ad2SJack F Vogel break;
47708cfa0ad2SJack F Vogel case 3:
47718cfa0ad2SJack F Vogel sector_size = ICH_FLASH_SEG_SIZE_64K;
47729d81738fSJack F Vogel iteration = 1;
47738cfa0ad2SJack F Vogel break;
47748cfa0ad2SJack F Vogel default:
47756ab6bfe3SJack F Vogel return -E1000_ERR_NVM;
47768cfa0ad2SJack F Vogel }
47778cfa0ad2SJack F Vogel
47788cfa0ad2SJack F Vogel /* Start with the base address, then add the sector offset. */
47798cfa0ad2SJack F Vogel flash_linear_addr = hw->nvm.flash_base_addr;
47804edd8523SJack F Vogel flash_linear_addr += (bank) ? flash_bank_size : 0;
47818cfa0ad2SJack F Vogel
47828cfa0ad2SJack F Vogel for (j = 0; j < iteration; j++) {
47838cfa0ad2SJack F Vogel do {
47847609433eSJack F Vogel u32 timeout = ICH_FLASH_ERASE_COMMAND_TIMEOUT;
47857609433eSJack F Vogel
47868cfa0ad2SJack F Vogel /* Steps */
47878cfa0ad2SJack F Vogel ret_val = e1000_flash_cycle_init_ich8lan(hw);
47888cfa0ad2SJack F Vogel if (ret_val)
47896ab6bfe3SJack F Vogel return ret_val;
47908cfa0ad2SJack F Vogel
47916ab6bfe3SJack F Vogel /* Write a value 11 (block Erase) in Flash
47928cfa0ad2SJack F Vogel * Cycle field in hw flash control
47938cfa0ad2SJack F Vogel */
4794295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt)
47958cc64f1eSJack F Vogel hsflctl.regval =
4796c80429ceSEric Joyner E1000_READ_FLASH_REG(hw,
4797c80429ceSEric Joyner ICH_FLASH_HSFSTS)>>16;
4798c80429ceSEric Joyner else
4799c80429ceSEric Joyner hsflctl.regval =
4800c80429ceSEric Joyner E1000_READ_FLASH_REG16(hw,
4801c80429ceSEric Joyner ICH_FLASH_HSFCTL);
48028cc64f1eSJack F Vogel
48038cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE;
4804295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt)
4805c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
4806c80429ceSEric Joyner hsflctl.regval << 16);
4807c80429ceSEric Joyner else
4808daf9197cSJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL,
48098cfa0ad2SJack F Vogel hsflctl.regval);
48108cfa0ad2SJack F Vogel
48116ab6bfe3SJack F Vogel /* Write the last 24 bits of an index within the
48128cfa0ad2SJack F Vogel * block into Flash Linear address field in Flash
48138cfa0ad2SJack F Vogel * Address.
48148cfa0ad2SJack F Vogel */
48158cfa0ad2SJack F Vogel flash_linear_addr += (j * sector_size);
4816daf9197cSJack F Vogel E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR,
48178cfa0ad2SJack F Vogel flash_linear_addr);
48188cfa0ad2SJack F Vogel
48197609433eSJack F Vogel ret_val = e1000_flash_cycle_ich8lan(hw, timeout);
4820daf9197cSJack F Vogel if (ret_val == E1000_SUCCESS)
48218cfa0ad2SJack F Vogel break;
4822daf9197cSJack F Vogel
48236ab6bfe3SJack F Vogel /* Check if FCERR is set to 1. If 1,
48248cfa0ad2SJack F Vogel * clear it and try the whole sequence
48258cfa0ad2SJack F Vogel * a few more times else Done
48268cfa0ad2SJack F Vogel */
48278cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw,
48288cfa0ad2SJack F Vogel ICH_FLASH_HSFSTS);
48296ab6bfe3SJack F Vogel if (hsfsts.hsf_status.flcerr)
4830daf9197cSJack F Vogel /* repeat for some time before giving up */
48318cfa0ad2SJack F Vogel continue;
48326ab6bfe3SJack F Vogel else if (!hsfsts.hsf_status.flcdone)
48336ab6bfe3SJack F Vogel return ret_val;
48348cfa0ad2SJack F Vogel } while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT);
48358cfa0ad2SJack F Vogel }
48368cfa0ad2SJack F Vogel
48376ab6bfe3SJack F Vogel return E1000_SUCCESS;
48388cfa0ad2SJack F Vogel }
48398cfa0ad2SJack F Vogel
48408cfa0ad2SJack F Vogel /**
48418cfa0ad2SJack F Vogel * e1000_valid_led_default_ich8lan - Set the default LED settings
48428cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
48438cfa0ad2SJack F Vogel * @data: Pointer to the LED settings
48448cfa0ad2SJack F Vogel *
48458cfa0ad2SJack F Vogel * Reads the LED default settings from the NVM to data. If the NVM LED
48468cfa0ad2SJack F Vogel * settings is all 0's or F's, set the LED default to a valid LED default
48478cfa0ad2SJack F Vogel * setting.
48488cfa0ad2SJack F Vogel **/
e1000_valid_led_default_ich8lan(struct e1000_hw * hw,u16 * data)48498cfa0ad2SJack F Vogel static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data)
48508cfa0ad2SJack F Vogel {
48518cfa0ad2SJack F Vogel s32 ret_val;
48528cfa0ad2SJack F Vogel
48538cfa0ad2SJack F Vogel DEBUGFUNC("e1000_valid_led_default_ich8lan");
48548cfa0ad2SJack F Vogel
48558cfa0ad2SJack F Vogel ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
48568cfa0ad2SJack F Vogel if (ret_val) {
48578cfa0ad2SJack F Vogel DEBUGOUT("NVM Read Error\n");
48586ab6bfe3SJack F Vogel return ret_val;
48598cfa0ad2SJack F Vogel }
48608cfa0ad2SJack F Vogel
48614dab5c37SJack F Vogel if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
48628cfa0ad2SJack F Vogel *data = ID_LED_DEFAULT_ICH8LAN;
48638cfa0ad2SJack F Vogel
48646ab6bfe3SJack F Vogel return E1000_SUCCESS;
48658cfa0ad2SJack F Vogel }
48668cfa0ad2SJack F Vogel
48678cfa0ad2SJack F Vogel /**
48689d81738fSJack F Vogel * e1000_id_led_init_pchlan - store LED configurations
48699d81738fSJack F Vogel * @hw: pointer to the HW structure
48709d81738fSJack F Vogel *
48719d81738fSJack F Vogel * PCH does not control LEDs via the LEDCTL register, rather it uses
48729d81738fSJack F Vogel * the PHY LED configuration register.
48739d81738fSJack F Vogel *
48749d81738fSJack F Vogel * PCH also does not have an "always on" or "always off" mode which
48759d81738fSJack F Vogel * complicates the ID feature. Instead of using the "on" mode to indicate
48769d81738fSJack F Vogel * in ledctl_mode2 the LEDs to use for ID (see e1000_id_led_init_generic()),
48779d81738fSJack F Vogel * use "link_up" mode. The LEDs will still ID on request if there is no
48789d81738fSJack F Vogel * link based on logic in e1000_led_[on|off]_pchlan().
48799d81738fSJack F Vogel **/
e1000_id_led_init_pchlan(struct e1000_hw * hw)48809d81738fSJack F Vogel static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw)
48819d81738fSJack F Vogel {
48829d81738fSJack F Vogel struct e1000_mac_info *mac = &hw->mac;
48839d81738fSJack F Vogel s32 ret_val;
48849d81738fSJack F Vogel const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP;
48859d81738fSJack F Vogel const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT;
48869d81738fSJack F Vogel u16 data, i, temp, shift;
48879d81738fSJack F Vogel
48889d81738fSJack F Vogel DEBUGFUNC("e1000_id_led_init_pchlan");
48899d81738fSJack F Vogel
48909d81738fSJack F Vogel /* Get default ID LED modes */
48919d81738fSJack F Vogel ret_val = hw->nvm.ops.valid_led_default(hw, &data);
48929d81738fSJack F Vogel if (ret_val)
48936ab6bfe3SJack F Vogel return ret_val;
48949d81738fSJack F Vogel
48959d81738fSJack F Vogel mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL);
48969d81738fSJack F Vogel mac->ledctl_mode1 = mac->ledctl_default;
48979d81738fSJack F Vogel mac->ledctl_mode2 = mac->ledctl_default;
48989d81738fSJack F Vogel
48999d81738fSJack F Vogel for (i = 0; i < 4; i++) {
49009d81738fSJack F Vogel temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK;
49019d81738fSJack F Vogel shift = (i * 5);
49029d81738fSJack F Vogel switch (temp) {
49039d81738fSJack F Vogel case ID_LED_ON1_DEF2:
49049d81738fSJack F Vogel case ID_LED_ON1_ON2:
49059d81738fSJack F Vogel case ID_LED_ON1_OFF2:
49069d81738fSJack F Vogel mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
49079d81738fSJack F Vogel mac->ledctl_mode1 |= (ledctl_on << shift);
49089d81738fSJack F Vogel break;
49099d81738fSJack F Vogel case ID_LED_OFF1_DEF2:
49109d81738fSJack F Vogel case ID_LED_OFF1_ON2:
49119d81738fSJack F Vogel case ID_LED_OFF1_OFF2:
49129d81738fSJack F Vogel mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
49139d81738fSJack F Vogel mac->ledctl_mode1 |= (ledctl_off << shift);
49149d81738fSJack F Vogel break;
49159d81738fSJack F Vogel default:
49169d81738fSJack F Vogel /* Do nothing */
49179d81738fSJack F Vogel break;
49189d81738fSJack F Vogel }
49199d81738fSJack F Vogel switch (temp) {
49209d81738fSJack F Vogel case ID_LED_DEF1_ON2:
49219d81738fSJack F Vogel case ID_LED_ON1_ON2:
49229d81738fSJack F Vogel case ID_LED_OFF1_ON2:
49239d81738fSJack F Vogel mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
49249d81738fSJack F Vogel mac->ledctl_mode2 |= (ledctl_on << shift);
49259d81738fSJack F Vogel break;
49269d81738fSJack F Vogel case ID_LED_DEF1_OFF2:
49279d81738fSJack F Vogel case ID_LED_ON1_OFF2:
49289d81738fSJack F Vogel case ID_LED_OFF1_OFF2:
49299d81738fSJack F Vogel mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
49309d81738fSJack F Vogel mac->ledctl_mode2 |= (ledctl_off << shift);
49319d81738fSJack F Vogel break;
49329d81738fSJack F Vogel default:
49339d81738fSJack F Vogel /* Do nothing */
49349d81738fSJack F Vogel break;
49359d81738fSJack F Vogel }
49369d81738fSJack F Vogel }
49379d81738fSJack F Vogel
49386ab6bfe3SJack F Vogel return E1000_SUCCESS;
49399d81738fSJack F Vogel }
49409d81738fSJack F Vogel
49419d81738fSJack F Vogel /**
49428cfa0ad2SJack F Vogel * e1000_get_bus_info_ich8lan - Get/Set the bus type and width
49438cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
49448cfa0ad2SJack F Vogel *
49458cfa0ad2SJack F Vogel * ICH8 use the PCI Express bus, but does not contain a PCI Express Capability
4946cef367e6SEitan Adler * register, so the bus width is hard coded.
49478cfa0ad2SJack F Vogel **/
e1000_get_bus_info_ich8lan(struct e1000_hw * hw)49488cfa0ad2SJack F Vogel static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw)
49498cfa0ad2SJack F Vogel {
49508cfa0ad2SJack F Vogel struct e1000_bus_info *bus = &hw->bus;
49518cfa0ad2SJack F Vogel s32 ret_val;
49528cfa0ad2SJack F Vogel
49538cfa0ad2SJack F Vogel DEBUGFUNC("e1000_get_bus_info_ich8lan");
49548cfa0ad2SJack F Vogel
49558cfa0ad2SJack F Vogel ret_val = e1000_get_bus_info_pcie_generic(hw);
49568cfa0ad2SJack F Vogel
49576ab6bfe3SJack F Vogel /* ICH devices are "PCI Express"-ish. They have
49588cfa0ad2SJack F Vogel * a configuration space, but do not contain
49598cfa0ad2SJack F Vogel * PCI Express Capability registers, so bus width
49608cfa0ad2SJack F Vogel * must be hardcoded.
49618cfa0ad2SJack F Vogel */
49628cfa0ad2SJack F Vogel if (bus->width == e1000_bus_width_unknown)
49638cfa0ad2SJack F Vogel bus->width = e1000_bus_width_pcie_x1;
49648cfa0ad2SJack F Vogel
49658cfa0ad2SJack F Vogel return ret_val;
49668cfa0ad2SJack F Vogel }
49678cfa0ad2SJack F Vogel
49688cfa0ad2SJack F Vogel /**
49698cfa0ad2SJack F Vogel * e1000_reset_hw_ich8lan - Reset the hardware
49708cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
49718cfa0ad2SJack F Vogel *
49728cfa0ad2SJack F Vogel * Does a full reset of the hardware which includes a reset of the PHY and
49738cfa0ad2SJack F Vogel * MAC.
49748cfa0ad2SJack F Vogel **/
e1000_reset_hw_ich8lan(struct e1000_hw * hw)49758cfa0ad2SJack F Vogel static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
49768cfa0ad2SJack F Vogel {
49774edd8523SJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
49786ab6bfe3SJack F Vogel u16 kum_cfg;
49796ab6bfe3SJack F Vogel u32 ctrl, reg;
49808cfa0ad2SJack F Vogel s32 ret_val;
4981d50f362bSGuinan Sun u16 pci_cfg;
49828cfa0ad2SJack F Vogel
49838cfa0ad2SJack F Vogel DEBUGFUNC("e1000_reset_hw_ich8lan");
49848cfa0ad2SJack F Vogel
49856ab6bfe3SJack F Vogel /* Prevent the PCI-E bus from sticking if there is no TLP connection
49868cfa0ad2SJack F Vogel * on the last TLP read/write transaction when MAC is reset.
49878cfa0ad2SJack F Vogel */
49888cfa0ad2SJack F Vogel ret_val = e1000_disable_pcie_master_generic(hw);
4989daf9197cSJack F Vogel if (ret_val)
49908cfa0ad2SJack F Vogel DEBUGOUT("PCI-E Master disable polling has failed.\n");
49918cfa0ad2SJack F Vogel
49928cfa0ad2SJack F Vogel DEBUGOUT("Masking off all interrupts\n");
49938cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
49948cfa0ad2SJack F Vogel
49956ab6bfe3SJack F Vogel /* Disable the Transmit and Receive units. Then delay to allow
49968cfa0ad2SJack F Vogel * any pending transactions to complete before we hit the MAC
49978cfa0ad2SJack F Vogel * with the global reset.
49988cfa0ad2SJack F Vogel */
49998cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_RCTL, 0);
50008cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
50018cfa0ad2SJack F Vogel E1000_WRITE_FLUSH(hw);
50028cfa0ad2SJack F Vogel
50038cfa0ad2SJack F Vogel msec_delay(10);
50048cfa0ad2SJack F Vogel
50058cfa0ad2SJack F Vogel /* Workaround for ICH8 bit corruption issue in FIFO memory */
50068cfa0ad2SJack F Vogel if (hw->mac.type == e1000_ich8lan) {
50078cfa0ad2SJack F Vogel /* Set Tx and Rx buffer allocation to 8k apiece. */
50088cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PBA, E1000_PBA_8K);
50098cfa0ad2SJack F Vogel /* Set Packet Buffer Size to 16k. */
50108cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PBS, E1000_PBS_16K);
50118cfa0ad2SJack F Vogel }
50128cfa0ad2SJack F Vogel
50134edd8523SJack F Vogel if (hw->mac.type == e1000_pchlan) {
50144edd8523SJack F Vogel /* Save the NVM K1 bit setting*/
50156ab6bfe3SJack F Vogel ret_val = e1000_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, &kum_cfg);
50164edd8523SJack F Vogel if (ret_val)
50174edd8523SJack F Vogel return ret_val;
50184edd8523SJack F Vogel
50196ab6bfe3SJack F Vogel if (kum_cfg & E1000_NVM_K1_ENABLE)
50201bbdc25fSKevin Bowling dev_spec->nvm_k1_enabled = true;
50214edd8523SJack F Vogel else
50221bbdc25fSKevin Bowling dev_spec->nvm_k1_enabled = false;
50234edd8523SJack F Vogel }
50244edd8523SJack F Vogel
50258cfa0ad2SJack F Vogel ctrl = E1000_READ_REG(hw, E1000_CTRL);
50268cfa0ad2SJack F Vogel
50277d9119bdSJack F Vogel if (!hw->phy.ops.check_reset_block(hw)) {
50286ab6bfe3SJack F Vogel /* Full-chip reset requires MAC and PHY reset at the same
50298cfa0ad2SJack F Vogel * time to make sure the interface between MAC and the
50308cfa0ad2SJack F Vogel * external PHY is reset.
50318cfa0ad2SJack F Vogel */
50328cfa0ad2SJack F Vogel ctrl |= E1000_CTRL_PHY_RST;
50337d9119bdSJack F Vogel
50346ab6bfe3SJack F Vogel /* Gate automatic PHY configuration by hardware on
50357d9119bdSJack F Vogel * non-managed 82579
50367d9119bdSJack F Vogel */
50377d9119bdSJack F Vogel if ((hw->mac.type == e1000_pch2lan) &&
50387d9119bdSJack F Vogel !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))
50391bbdc25fSKevin Bowling e1000_gate_hw_phy_config_ich8lan(hw, true);
50408cfa0ad2SJack F Vogel }
50418cfa0ad2SJack F Vogel ret_val = e1000_acquire_swflag_ich8lan(hw);
5042d50f362bSGuinan Sun
5043d50f362bSGuinan Sun /* Read from EXTCNF_CTRL in e1000_acquire_swflag_ich8lan function
5044d50f362bSGuinan Sun * may occur during global reset and cause system hang.
5045d50f362bSGuinan Sun * Configuration space access creates the needed delay.
5046d50f362bSGuinan Sun * Write to E1000_STRAP RO register E1000_PCI_VENDOR_ID_REGISTER value
5047d50f362bSGuinan Sun * insures configuration space read is done before global reset.
5048d50f362bSGuinan Sun */
5049d50f362bSGuinan Sun e1000_read_pci_cfg(hw, E1000_PCI_VENDOR_ID_REGISTER, &pci_cfg);
5050d50f362bSGuinan Sun E1000_WRITE_REG(hw, E1000_STRAP, pci_cfg);
5051daf9197cSJack F Vogel DEBUGOUT("Issuing a global reset to ich8lan\n");
50528cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_RST));
50534dab5c37SJack F Vogel /* cannot issue a flush here because it hangs the hardware */
50548cfa0ad2SJack F Vogel msec_delay(20);
50558cfa0ad2SJack F Vogel
5056d50f362bSGuinan Sun /* Configuration space access improve HW level time sync mechanism.
5057d50f362bSGuinan Sun * Write to E1000_STRAP RO register E1000_PCI_VENDOR_ID_REGISTER
5058d50f362bSGuinan Sun * value to insure configuration space read is done
5059d50f362bSGuinan Sun * before any access to mac register.
5060d50f362bSGuinan Sun */
5061d50f362bSGuinan Sun e1000_read_pci_cfg(hw, E1000_PCI_VENDOR_ID_REGISTER, &pci_cfg);
5062d50f362bSGuinan Sun E1000_WRITE_REG(hw, E1000_STRAP, pci_cfg);
5063d50f362bSGuinan Sun
50646ab6bfe3SJack F Vogel /* Set Phy Config Counter to 50msec */
50656ab6bfe3SJack F Vogel if (hw->mac.type == e1000_pch2lan) {
50666ab6bfe3SJack F Vogel reg = E1000_READ_REG(hw, E1000_FEXTNVM3);
50676ab6bfe3SJack F Vogel reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK;
50686ab6bfe3SJack F Vogel reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
50696ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM3, reg);
50706ab6bfe3SJack F Vogel }
50716ab6bfe3SJack F Vogel
50729d81738fSJack F Vogel
50737d9119bdSJack F Vogel if (ctrl & E1000_CTRL_PHY_RST) {
50749d81738fSJack F Vogel ret_val = hw->phy.ops.get_cfg_done(hw);
50754edd8523SJack F Vogel if (ret_val)
50766ab6bfe3SJack F Vogel return ret_val;
50774edd8523SJack F Vogel
50787d9119bdSJack F Vogel ret_val = e1000_post_phy_reset_ich8lan(hw);
50794edd8523SJack F Vogel if (ret_val)
50806ab6bfe3SJack F Vogel return ret_val;
50817d9119bdSJack F Vogel }
50827d9119bdSJack F Vogel
50836ab6bfe3SJack F Vogel /* For PCH, this write will make sure that any noise
50844edd8523SJack F Vogel * will be detected as a CRC error and be dropped rather than show up
50854edd8523SJack F Vogel * as a bad packet to the DMA engine.
50864edd8523SJack F Vogel */
50874edd8523SJack F Vogel if (hw->mac.type == e1000_pchlan)
50884edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_CRC_OFFSET, 0x65656565);
50898cfa0ad2SJack F Vogel
50908cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
5091730d3130SJack F Vogel E1000_READ_REG(hw, E1000_ICR);
50928cfa0ad2SJack F Vogel
50936ab6bfe3SJack F Vogel reg = E1000_READ_REG(hw, E1000_KABGTXD);
50946ab6bfe3SJack F Vogel reg |= E1000_KABGTXD_BGSQLBIAS;
50956ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_KABGTXD, reg);
50968cfa0ad2SJack F Vogel
50976ab6bfe3SJack F Vogel return E1000_SUCCESS;
50988cfa0ad2SJack F Vogel }
50998cfa0ad2SJack F Vogel
51008cfa0ad2SJack F Vogel /**
51018cfa0ad2SJack F Vogel * e1000_init_hw_ich8lan - Initialize the hardware
51028cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
51038cfa0ad2SJack F Vogel *
51048cfa0ad2SJack F Vogel * Prepares the hardware for transmit and receive by doing the following:
51058cfa0ad2SJack F Vogel * - initialize hardware bits
51068cfa0ad2SJack F Vogel * - initialize LED identification
51078cfa0ad2SJack F Vogel * - setup receive address registers
51088cfa0ad2SJack F Vogel * - setup flow control
51098cfa0ad2SJack F Vogel * - setup transmit descriptors
51108cfa0ad2SJack F Vogel * - clear statistics
51118cfa0ad2SJack F Vogel **/
e1000_init_hw_ich8lan(struct e1000_hw * hw)51128cfa0ad2SJack F Vogel static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
51138cfa0ad2SJack F Vogel {
51148cfa0ad2SJack F Vogel struct e1000_mac_info *mac = &hw->mac;
51158cfa0ad2SJack F Vogel u32 ctrl_ext, txdctl, snoop;
51168cfa0ad2SJack F Vogel s32 ret_val;
51178cfa0ad2SJack F Vogel u16 i;
51188cfa0ad2SJack F Vogel
51198cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_hw_ich8lan");
51208cfa0ad2SJack F Vogel
51218cfa0ad2SJack F Vogel e1000_initialize_hw_bits_ich8lan(hw);
51228cfa0ad2SJack F Vogel
51238cfa0ad2SJack F Vogel /* Initialize identification LED */
5124d035aa2dSJack F Vogel ret_val = mac->ops.id_led_init(hw);
51256ab6bfe3SJack F Vogel /* An error is not fatal and we should not stop init due to this */
5126d035aa2dSJack F Vogel if (ret_val)
5127d035aa2dSJack F Vogel DEBUGOUT("Error initializing identification LED\n");
51288cfa0ad2SJack F Vogel
51298cfa0ad2SJack F Vogel /* Setup the receive address. */
51308cfa0ad2SJack F Vogel e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
51318cfa0ad2SJack F Vogel
51328cfa0ad2SJack F Vogel /* Zero out the Multicast HASH table */
51338cfa0ad2SJack F Vogel DEBUGOUT("Zeroing the MTA\n");
51348cfa0ad2SJack F Vogel for (i = 0; i < mac->mta_reg_count; i++)
51358cfa0ad2SJack F Vogel E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
51368cfa0ad2SJack F Vogel
51376ab6bfe3SJack F Vogel /* The 82578 Rx buffer will stall if wakeup is enabled in host and
51384dab5c37SJack F Vogel * the ME. Disable wakeup by clearing the host wakeup bit.
51399d81738fSJack F Vogel * Reset the phy after disabling host wakeup to reset the Rx buffer.
51409d81738fSJack F Vogel */
51419d81738fSJack F Vogel if (hw->phy.type == e1000_phy_82578) {
51424dab5c37SJack F Vogel hw->phy.ops.read_reg(hw, BM_PORT_GEN_CFG, &i);
51434dab5c37SJack F Vogel i &= ~BM_WUC_HOST_WU_BIT;
51444dab5c37SJack F Vogel hw->phy.ops.write_reg(hw, BM_PORT_GEN_CFG, i);
51459d81738fSJack F Vogel ret_val = e1000_phy_hw_reset_ich8lan(hw);
51469d81738fSJack F Vogel if (ret_val)
51479d81738fSJack F Vogel return ret_val;
51489d81738fSJack F Vogel }
51499d81738fSJack F Vogel
51508cfa0ad2SJack F Vogel /* Setup link and flow control */
51518cfa0ad2SJack F Vogel ret_val = mac->ops.setup_link(hw);
51528cfa0ad2SJack F Vogel
51538cfa0ad2SJack F Vogel /* Set the transmit descriptor write-back policy for both queues */
51548cfa0ad2SJack F Vogel txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
51557609433eSJack F Vogel txdctl = ((txdctl & ~E1000_TXDCTL_WTHRESH) |
51567609433eSJack F Vogel E1000_TXDCTL_FULL_TX_DESC_WB);
51577609433eSJack F Vogel txdctl = ((txdctl & ~E1000_TXDCTL_PTHRESH) |
51587609433eSJack F Vogel E1000_TXDCTL_MAX_TX_DESC_PREFETCH);
51598cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);
51608cfa0ad2SJack F Vogel txdctl = E1000_READ_REG(hw, E1000_TXDCTL(1));
51617609433eSJack F Vogel txdctl = ((txdctl & ~E1000_TXDCTL_WTHRESH) |
51627609433eSJack F Vogel E1000_TXDCTL_FULL_TX_DESC_WB);
51637609433eSJack F Vogel txdctl = ((txdctl & ~E1000_TXDCTL_PTHRESH) |
51647609433eSJack F Vogel E1000_TXDCTL_MAX_TX_DESC_PREFETCH);
51658cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TXDCTL(1), txdctl);
51668cfa0ad2SJack F Vogel
51676ab6bfe3SJack F Vogel /* ICH8 has opposite polarity of no_snoop bits.
51688cfa0ad2SJack F Vogel * By default, we should use snoop behavior.
51698cfa0ad2SJack F Vogel */
51708cfa0ad2SJack F Vogel if (mac->type == e1000_ich8lan)
51718cfa0ad2SJack F Vogel snoop = PCIE_ICH8_SNOOP_ALL;
51728cfa0ad2SJack F Vogel else
51738cfa0ad2SJack F Vogel snoop = (u32) ~(PCIE_NO_SNOOP_ALL);
51748cfa0ad2SJack F Vogel e1000_set_pcie_no_snoop_generic(hw, snoop);
51758cfa0ad2SJack F Vogel
517656365902SKevin Bowling /* ungate DMA clock to avoid packet loss */
517756365902SKevin Bowling if (mac->type >= e1000_pch_tgp) {
517856365902SKevin Bowling uint32_t fflt_dbg = E1000_READ_REG(hw, E1000_FFLT_DBG);
517956365902SKevin Bowling fflt_dbg |= (1 << 12);
518056365902SKevin Bowling E1000_WRITE_REG(hw, E1000_FFLT_DBG, fflt_dbg);
518156365902SKevin Bowling }
518256365902SKevin Bowling
51838cfa0ad2SJack F Vogel ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
51848cfa0ad2SJack F Vogel ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
51858cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
51868cfa0ad2SJack F Vogel
51876ab6bfe3SJack F Vogel /* Clear all of the statistics registers (clear on read). It is
51888cfa0ad2SJack F Vogel * important that we do this after we have tried to establish link
51898cfa0ad2SJack F Vogel * because the symbol error count will increment wildly if there
51908cfa0ad2SJack F Vogel * is no link.
51918cfa0ad2SJack F Vogel */
51928cfa0ad2SJack F Vogel e1000_clear_hw_cntrs_ich8lan(hw);
51938cfa0ad2SJack F Vogel
51948cfa0ad2SJack F Vogel return ret_val;
51958cfa0ad2SJack F Vogel }
51966ab6bfe3SJack F Vogel
51978cfa0ad2SJack F Vogel /**
51988cfa0ad2SJack F Vogel * e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits
51998cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
52008cfa0ad2SJack F Vogel *
52018cfa0ad2SJack F Vogel * Sets/Clears required hardware bits necessary for correctly setting up the
52028cfa0ad2SJack F Vogel * hardware for transmit and receive.
52038cfa0ad2SJack F Vogel **/
e1000_initialize_hw_bits_ich8lan(struct e1000_hw * hw)52048cfa0ad2SJack F Vogel static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
52058cfa0ad2SJack F Vogel {
52068cfa0ad2SJack F Vogel u32 reg;
52078cfa0ad2SJack F Vogel
52088cfa0ad2SJack F Vogel DEBUGFUNC("e1000_initialize_hw_bits_ich8lan");
52098cfa0ad2SJack F Vogel
52108cfa0ad2SJack F Vogel /* Extended Device Control */
52118cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
52128cfa0ad2SJack F Vogel reg |= (1 << 22);
52139d81738fSJack F Vogel /* Enable PHY low-power state when MAC is at D3 w/o WoL */
52149d81738fSJack F Vogel if (hw->mac.type >= e1000_pchlan)
52159d81738fSJack F Vogel reg |= E1000_CTRL_EXT_PHYPDEN;
52168cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
52178cfa0ad2SJack F Vogel
52188cfa0ad2SJack F Vogel /* Transmit Descriptor Control 0 */
52198cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_TXDCTL(0));
52208cfa0ad2SJack F Vogel reg |= (1 << 22);
52218cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg);
52228cfa0ad2SJack F Vogel
52238cfa0ad2SJack F Vogel /* Transmit Descriptor Control 1 */
52248cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_TXDCTL(1));
52258cfa0ad2SJack F Vogel reg |= (1 << 22);
52268cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg);
52278cfa0ad2SJack F Vogel
52288cfa0ad2SJack F Vogel /* Transmit Arbitration Control 0 */
52298cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_TARC(0));
52308cfa0ad2SJack F Vogel if (hw->mac.type == e1000_ich8lan)
52318cfa0ad2SJack F Vogel reg |= (1 << 28) | (1 << 29);
52328cfa0ad2SJack F Vogel reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27);
52338cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TARC(0), reg);
52348cfa0ad2SJack F Vogel
52358cfa0ad2SJack F Vogel /* Transmit Arbitration Control 1 */
52368cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_TARC(1));
52378cfa0ad2SJack F Vogel if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR)
52388cfa0ad2SJack F Vogel reg &= ~(1 << 28);
52398cfa0ad2SJack F Vogel else
52408cfa0ad2SJack F Vogel reg |= (1 << 28);
52418cfa0ad2SJack F Vogel reg |= (1 << 24) | (1 << 26) | (1 << 30);
52428cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TARC(1), reg);
52438cfa0ad2SJack F Vogel
52448cfa0ad2SJack F Vogel /* Device Status */
52458cfa0ad2SJack F Vogel if (hw->mac.type == e1000_ich8lan) {
52468cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_STATUS);
52478f07d847SEitan Adler reg &= ~(1U << 31);
52488cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_STATUS, reg);
52498cfa0ad2SJack F Vogel }
52508cfa0ad2SJack F Vogel
52516ab6bfe3SJack F Vogel /* work-around descriptor data corruption issue during nfs v2 udp
52528ec87fc5SJack F Vogel * traffic, just disable the nfs filtering capability
52538ec87fc5SJack F Vogel */
52548ec87fc5SJack F Vogel reg = E1000_READ_REG(hw, E1000_RFCTL);
52558ec87fc5SJack F Vogel reg |= (E1000_RFCTL_NFSW_DIS | E1000_RFCTL_NFSR_DIS);
52567609433eSJack F Vogel
52576ab6bfe3SJack F Vogel /* Disable IPv6 extension header parsing because some malformed
52586ab6bfe3SJack F Vogel * IPv6 headers can hang the Rx.
52596ab6bfe3SJack F Vogel */
52606ab6bfe3SJack F Vogel if (hw->mac.type == e1000_ich8lan)
52616ab6bfe3SJack F Vogel reg |= (E1000_RFCTL_IPV6_EX_DIS | E1000_RFCTL_NEW_IPV6_EXT_DIS);
52628ec87fc5SJack F Vogel E1000_WRITE_REG(hw, E1000_RFCTL, reg);
52638ec87fc5SJack F Vogel
52646ab6bfe3SJack F Vogel /* Enable ECC on Lynxpoint */
5265295df609SEric Joyner if (hw->mac.type >= e1000_pch_lpt) {
52666ab6bfe3SJack F Vogel reg = E1000_READ_REG(hw, E1000_PBECCSTS);
52676ab6bfe3SJack F Vogel reg |= E1000_PBECCSTS_ECC_ENABLE;
52686ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_PBECCSTS, reg);
52696ab6bfe3SJack F Vogel
52706ab6bfe3SJack F Vogel reg = E1000_READ_REG(hw, E1000_CTRL);
52716ab6bfe3SJack F Vogel reg |= E1000_CTRL_MEHE;
52726ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, reg);
52736ab6bfe3SJack F Vogel }
52746ab6bfe3SJack F Vogel
52758cfa0ad2SJack F Vogel return;
52768cfa0ad2SJack F Vogel }
52778cfa0ad2SJack F Vogel
52788cfa0ad2SJack F Vogel /**
52798cfa0ad2SJack F Vogel * e1000_setup_link_ich8lan - Setup flow control and link settings
52808cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
52818cfa0ad2SJack F Vogel *
52828cfa0ad2SJack F Vogel * Determines which flow control settings to use, then configures flow
52838cfa0ad2SJack F Vogel * control. Calls the appropriate media-specific link configuration
52848cfa0ad2SJack F Vogel * function. Assuming the adapter has a valid link partner, a valid link
52858cfa0ad2SJack F Vogel * should be established. Assumes the hardware has previously been reset
52868cfa0ad2SJack F Vogel * and the transmitter and receiver are not enabled.
52878cfa0ad2SJack F Vogel **/
e1000_setup_link_ich8lan(struct e1000_hw * hw)52888cfa0ad2SJack F Vogel static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
52898cfa0ad2SJack F Vogel {
52906ab6bfe3SJack F Vogel s32 ret_val;
52918cfa0ad2SJack F Vogel
52928cfa0ad2SJack F Vogel DEBUGFUNC("e1000_setup_link_ich8lan");
52938cfa0ad2SJack F Vogel
52946ab6bfe3SJack F Vogel /* ICH parts do not have a word in the NVM to determine
52958cfa0ad2SJack F Vogel * the default flow control setting, so we explicitly
52968cfa0ad2SJack F Vogel * set it to full.
52978cfa0ad2SJack F Vogel */
5298daf9197cSJack F Vogel if (hw->fc.requested_mode == e1000_fc_default)
5299daf9197cSJack F Vogel hw->fc.requested_mode = e1000_fc_full;
53008cfa0ad2SJack F Vogel
53016ab6bfe3SJack F Vogel /* Save off the requested flow control mode for use later. Depending
5302daf9197cSJack F Vogel * on the link partner's capabilities, we may or may not use this mode.
5303daf9197cSJack F Vogel */
5304daf9197cSJack F Vogel hw->fc.current_mode = hw->fc.requested_mode;
53058cfa0ad2SJack F Vogel
5306daf9197cSJack F Vogel DEBUGOUT1("After fix-ups FlowControl is now = %x\n",
5307daf9197cSJack F Vogel hw->fc.current_mode);
53088cfa0ad2SJack F Vogel
530951569bd7SEric Joyner if (!hw->phy.ops.check_reset_block(hw)) {
53108cfa0ad2SJack F Vogel /* Continue to configure the copper link. */
53118cfa0ad2SJack F Vogel ret_val = hw->mac.ops.setup_physical_interface(hw);
53128cfa0ad2SJack F Vogel if (ret_val)
53136ab6bfe3SJack F Vogel return ret_val;
531451569bd7SEric Joyner }
53158cfa0ad2SJack F Vogel
53168cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
53179d81738fSJack F Vogel if ((hw->phy.type == e1000_phy_82578) ||
53187d9119bdSJack F Vogel (hw->phy.type == e1000_phy_82579) ||
53196ab6bfe3SJack F Vogel (hw->phy.type == e1000_phy_i217) ||
53209d81738fSJack F Vogel (hw->phy.type == e1000_phy_82577)) {
53217d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_FCRTV_PCH, hw->fc.refresh_time);
53227d9119bdSJack F Vogel
53239d81738fSJack F Vogel ret_val = hw->phy.ops.write_reg(hw,
53249d81738fSJack F Vogel PHY_REG(BM_PORT_CTRL_PAGE, 27),
53259d81738fSJack F Vogel hw->fc.pause_time);
53269d81738fSJack F Vogel if (ret_val)
53276ab6bfe3SJack F Vogel return ret_val;
53289d81738fSJack F Vogel }
53298cfa0ad2SJack F Vogel
53306ab6bfe3SJack F Vogel return e1000_set_fc_watermarks_generic(hw);
53318cfa0ad2SJack F Vogel }
53328cfa0ad2SJack F Vogel
53338cfa0ad2SJack F Vogel /**
53348cfa0ad2SJack F Vogel * e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface
53358cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
53368cfa0ad2SJack F Vogel *
53378cfa0ad2SJack F Vogel * Configures the kumeran interface to the PHY to wait the appropriate time
53388cfa0ad2SJack F Vogel * when polling the PHY, then call the generic setup_copper_link to finish
53398cfa0ad2SJack F Vogel * configuring the copper link.
53408cfa0ad2SJack F Vogel **/
e1000_setup_copper_link_ich8lan(struct e1000_hw * hw)53418cfa0ad2SJack F Vogel static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
53428cfa0ad2SJack F Vogel {
53438cfa0ad2SJack F Vogel u32 ctrl;
53448cfa0ad2SJack F Vogel s32 ret_val;
53458cfa0ad2SJack F Vogel u16 reg_data;
53468cfa0ad2SJack F Vogel
53478cfa0ad2SJack F Vogel DEBUGFUNC("e1000_setup_copper_link_ich8lan");
53488cfa0ad2SJack F Vogel
53498cfa0ad2SJack F Vogel ctrl = E1000_READ_REG(hw, E1000_CTRL);
53508cfa0ad2SJack F Vogel ctrl |= E1000_CTRL_SLU;
53518cfa0ad2SJack F Vogel ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
53528cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
53538cfa0ad2SJack F Vogel
53546ab6bfe3SJack F Vogel /* Set the mac to wait the maximum time between each iteration
53558cfa0ad2SJack F Vogel * and increase the max iterations when polling the phy;
53568cfa0ad2SJack F Vogel * this fixes erroneous timeouts at 10Mbps.
53578cfa0ad2SJack F Vogel */
53584edd8523SJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_TIMEOUTS,
53598cfa0ad2SJack F Vogel 0xFFFF);
53608cfa0ad2SJack F Vogel if (ret_val)
53616ab6bfe3SJack F Vogel return ret_val;
53629d81738fSJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw,
53639d81738fSJack F Vogel E1000_KMRNCTRLSTA_INBAND_PARAM,
53648cfa0ad2SJack F Vogel ®_data);
53658cfa0ad2SJack F Vogel if (ret_val)
53666ab6bfe3SJack F Vogel return ret_val;
53678cfa0ad2SJack F Vogel reg_data |= 0x3F;
53689d81738fSJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw,
53699d81738fSJack F Vogel E1000_KMRNCTRLSTA_INBAND_PARAM,
53708cfa0ad2SJack F Vogel reg_data);
53718cfa0ad2SJack F Vogel if (ret_val)
53726ab6bfe3SJack F Vogel return ret_val;
53738cfa0ad2SJack F Vogel
5374d035aa2dSJack F Vogel switch (hw->phy.type) {
5375d035aa2dSJack F Vogel case e1000_phy_igp_3:
53768cfa0ad2SJack F Vogel ret_val = e1000_copper_link_setup_igp(hw);
53778cfa0ad2SJack F Vogel if (ret_val)
53786ab6bfe3SJack F Vogel return ret_val;
5379d035aa2dSJack F Vogel break;
5380d035aa2dSJack F Vogel case e1000_phy_bm:
53819d81738fSJack F Vogel case e1000_phy_82578:
53828cfa0ad2SJack F Vogel ret_val = e1000_copper_link_setup_m88(hw);
53838cfa0ad2SJack F Vogel if (ret_val)
53846ab6bfe3SJack F Vogel return ret_val;
5385d035aa2dSJack F Vogel break;
53869d81738fSJack F Vogel case e1000_phy_82577:
53877d9119bdSJack F Vogel case e1000_phy_82579:
53889d81738fSJack F Vogel ret_val = e1000_copper_link_setup_82577(hw);
53899d81738fSJack F Vogel if (ret_val)
53906ab6bfe3SJack F Vogel return ret_val;
53919d81738fSJack F Vogel break;
5392d035aa2dSJack F Vogel case e1000_phy_ife:
53938cfa0ad2SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, IFE_PHY_MDIX_CONTROL,
53948cfa0ad2SJack F Vogel ®_data);
53958cfa0ad2SJack F Vogel if (ret_val)
53966ab6bfe3SJack F Vogel return ret_val;
53978cfa0ad2SJack F Vogel
53988cfa0ad2SJack F Vogel reg_data &= ~IFE_PMC_AUTO_MDIX;
53998cfa0ad2SJack F Vogel
54008cfa0ad2SJack F Vogel switch (hw->phy.mdix) {
54018cfa0ad2SJack F Vogel case 1:
54028cfa0ad2SJack F Vogel reg_data &= ~IFE_PMC_FORCE_MDIX;
54038cfa0ad2SJack F Vogel break;
54048cfa0ad2SJack F Vogel case 2:
54058cfa0ad2SJack F Vogel reg_data |= IFE_PMC_FORCE_MDIX;
54068cfa0ad2SJack F Vogel break;
54078cfa0ad2SJack F Vogel case 0:
54088cfa0ad2SJack F Vogel default:
54098cfa0ad2SJack F Vogel reg_data |= IFE_PMC_AUTO_MDIX;
54108cfa0ad2SJack F Vogel break;
54118cfa0ad2SJack F Vogel }
54128cfa0ad2SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_MDIX_CONTROL,
54138cfa0ad2SJack F Vogel reg_data);
54148cfa0ad2SJack F Vogel if (ret_val)
54156ab6bfe3SJack F Vogel return ret_val;
5416d035aa2dSJack F Vogel break;
5417d035aa2dSJack F Vogel default:
5418d035aa2dSJack F Vogel break;
54198cfa0ad2SJack F Vogel }
54208cfa0ad2SJack F Vogel
54216ab6bfe3SJack F Vogel return e1000_setup_copper_link_generic(hw);
54226ab6bfe3SJack F Vogel }
54236ab6bfe3SJack F Vogel
54246ab6bfe3SJack F Vogel /**
54256ab6bfe3SJack F Vogel * e1000_setup_copper_link_pch_lpt - Configure MAC/PHY interface
54266ab6bfe3SJack F Vogel * @hw: pointer to the HW structure
54276ab6bfe3SJack F Vogel *
54286ab6bfe3SJack F Vogel * Calls the PHY specific link setup function and then calls the
54296ab6bfe3SJack F Vogel * generic setup_copper_link to finish configuring the link for
54306ab6bfe3SJack F Vogel * Lynxpoint PCH devices
54316ab6bfe3SJack F Vogel **/
e1000_setup_copper_link_pch_lpt(struct e1000_hw * hw)54326ab6bfe3SJack F Vogel static s32 e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw)
54336ab6bfe3SJack F Vogel {
54346ab6bfe3SJack F Vogel u32 ctrl;
54356ab6bfe3SJack F Vogel s32 ret_val;
54366ab6bfe3SJack F Vogel
54376ab6bfe3SJack F Vogel DEBUGFUNC("e1000_setup_copper_link_pch_lpt");
54386ab6bfe3SJack F Vogel
54396ab6bfe3SJack F Vogel ctrl = E1000_READ_REG(hw, E1000_CTRL);
54406ab6bfe3SJack F Vogel ctrl |= E1000_CTRL_SLU;
54416ab6bfe3SJack F Vogel ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
54426ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
54436ab6bfe3SJack F Vogel
54446ab6bfe3SJack F Vogel ret_val = e1000_copper_link_setup_82577(hw);
54456ab6bfe3SJack F Vogel if (ret_val)
54468cfa0ad2SJack F Vogel return ret_val;
54476ab6bfe3SJack F Vogel
54486ab6bfe3SJack F Vogel return e1000_setup_copper_link_generic(hw);
54498cfa0ad2SJack F Vogel }
54508cfa0ad2SJack F Vogel
54518cfa0ad2SJack F Vogel /**
54528cfa0ad2SJack F Vogel * e1000_get_link_up_info_ich8lan - Get current link speed and duplex
54538cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
54548cfa0ad2SJack F Vogel * @speed: pointer to store current link speed
54558cfa0ad2SJack F Vogel * @duplex: pointer to store the current link duplex
54568cfa0ad2SJack F Vogel *
54578cfa0ad2SJack F Vogel * Calls the generic get_speed_and_duplex to retrieve the current link
54588cfa0ad2SJack F Vogel * information and then calls the Kumeran lock loss workaround for links at
54598cfa0ad2SJack F Vogel * gigabit speeds.
54608cfa0ad2SJack F Vogel **/
e1000_get_link_up_info_ich8lan(struct e1000_hw * hw,u16 * speed,u16 * duplex)54618cfa0ad2SJack F Vogel static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed,
54628cfa0ad2SJack F Vogel u16 *duplex)
54638cfa0ad2SJack F Vogel {
54648cfa0ad2SJack F Vogel s32 ret_val;
54658cfa0ad2SJack F Vogel
54668cfa0ad2SJack F Vogel DEBUGFUNC("e1000_get_link_up_info_ich8lan");
54678cfa0ad2SJack F Vogel
54688cfa0ad2SJack F Vogel ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex);
54698cfa0ad2SJack F Vogel if (ret_val)
54706ab6bfe3SJack F Vogel return ret_val;
54718cfa0ad2SJack F Vogel
54728cfa0ad2SJack F Vogel if ((hw->mac.type == e1000_ich8lan) &&
54738cfa0ad2SJack F Vogel (hw->phy.type == e1000_phy_igp_3) &&
54748cfa0ad2SJack F Vogel (*speed == SPEED_1000)) {
54758cfa0ad2SJack F Vogel ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw);
54768cfa0ad2SJack F Vogel }
54778cfa0ad2SJack F Vogel
54788cfa0ad2SJack F Vogel return ret_val;
54798cfa0ad2SJack F Vogel }
54808cfa0ad2SJack F Vogel
54818cfa0ad2SJack F Vogel /**
54828cfa0ad2SJack F Vogel * e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround
54838cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
54848cfa0ad2SJack F Vogel *
54858cfa0ad2SJack F Vogel * Work-around for 82566 Kumeran PCS lock loss:
54868cfa0ad2SJack F Vogel * On link status change (i.e. PCI reset, speed change) and link is up and
54878cfa0ad2SJack F Vogel * speed is gigabit-
54888cfa0ad2SJack F Vogel * 0) if workaround is optionally disabled do nothing
54898cfa0ad2SJack F Vogel * 1) wait 1ms for Kumeran link to come up
54908cfa0ad2SJack F Vogel * 2) check Kumeran Diagnostic register PCS lock loss bit
54918cfa0ad2SJack F Vogel * 3) if not set the link is locked (all is good), otherwise...
54928cfa0ad2SJack F Vogel * 4) reset the PHY
54938cfa0ad2SJack F Vogel * 5) repeat up to 10 times
54948cfa0ad2SJack F Vogel * Note: this is only called for IGP3 copper when speed is 1gb.
54958cfa0ad2SJack F Vogel **/
e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw * hw)54968cfa0ad2SJack F Vogel static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
54978cfa0ad2SJack F Vogel {
5498daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
54998cfa0ad2SJack F Vogel u32 phy_ctrl;
55006ab6bfe3SJack F Vogel s32 ret_val;
55018cfa0ad2SJack F Vogel u16 i, data;
55028cfa0ad2SJack F Vogel bool link;
55038cfa0ad2SJack F Vogel
55048cfa0ad2SJack F Vogel DEBUGFUNC("e1000_kmrn_lock_loss_workaround_ich8lan");
55058cfa0ad2SJack F Vogel
5506730d3130SJack F Vogel if (!dev_spec->kmrn_lock_loss_workaround_enabled)
55076ab6bfe3SJack F Vogel return E1000_SUCCESS;
55088cfa0ad2SJack F Vogel
55096ab6bfe3SJack F Vogel /* Make sure link is up before proceeding. If not just return.
55108cfa0ad2SJack F Vogel * Attempting this while link is negotiating fouled up link
55118cfa0ad2SJack F Vogel * stability
55128cfa0ad2SJack F Vogel */
55138cfa0ad2SJack F Vogel ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
55146ab6bfe3SJack F Vogel if (!link)
55156ab6bfe3SJack F Vogel return E1000_SUCCESS;
55168cfa0ad2SJack F Vogel
55178cfa0ad2SJack F Vogel for (i = 0; i < 10; i++) {
55188cfa0ad2SJack F Vogel /* read once to clear */
55198cfa0ad2SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data);
55208cfa0ad2SJack F Vogel if (ret_val)
55216ab6bfe3SJack F Vogel return ret_val;
55228cfa0ad2SJack F Vogel /* and again to get new status */
55238cfa0ad2SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data);
55248cfa0ad2SJack F Vogel if (ret_val)
55256ab6bfe3SJack F Vogel return ret_val;
55268cfa0ad2SJack F Vogel
55278cfa0ad2SJack F Vogel /* check for PCS lock */
55286ab6bfe3SJack F Vogel if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS))
55296ab6bfe3SJack F Vogel return E1000_SUCCESS;
55308cfa0ad2SJack F Vogel
55318cfa0ad2SJack F Vogel /* Issue PHY reset */
55328cfa0ad2SJack F Vogel hw->phy.ops.reset(hw);
55338cfa0ad2SJack F Vogel msec_delay_irq(5);
55348cfa0ad2SJack F Vogel }
55358cfa0ad2SJack F Vogel /* Disable GigE link negotiation */
55368cfa0ad2SJack F Vogel phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
55378cfa0ad2SJack F Vogel phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE |
55388cfa0ad2SJack F Vogel E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
55398cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
55408cfa0ad2SJack F Vogel
55416ab6bfe3SJack F Vogel /* Call gig speed drop workaround on Gig disable before accessing
55428cfa0ad2SJack F Vogel * any PHY registers
55438cfa0ad2SJack F Vogel */
55448cfa0ad2SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw);
55458cfa0ad2SJack F Vogel
55468cfa0ad2SJack F Vogel /* unable to acquire PCS lock */
55476ab6bfe3SJack F Vogel return -E1000_ERR_PHY;
55488cfa0ad2SJack F Vogel }
55498cfa0ad2SJack F Vogel
55508cfa0ad2SJack F Vogel /**
55518cfa0ad2SJack F Vogel * e1000_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state
55528cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
55538cfa0ad2SJack F Vogel * @state: boolean value used to set the current Kumeran workaround state
55548cfa0ad2SJack F Vogel *
55551bbdc25fSKevin Bowling * If ICH8, set the current Kumeran workaround state (enabled - true
55561bbdc25fSKevin Bowling * /disabled - false).
55578cfa0ad2SJack F Vogel **/
e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw * hw,bool state)55588cfa0ad2SJack F Vogel void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
55598cfa0ad2SJack F Vogel bool state)
55608cfa0ad2SJack F Vogel {
5561daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
55628cfa0ad2SJack F Vogel
55638cfa0ad2SJack F Vogel DEBUGFUNC("e1000_set_kmrn_lock_loss_workaround_ich8lan");
55648cfa0ad2SJack F Vogel
55658cfa0ad2SJack F Vogel if (hw->mac.type != e1000_ich8lan) {
55668cfa0ad2SJack F Vogel DEBUGOUT("Workaround applies to ICH8 only.\n");
5567daf9197cSJack F Vogel return;
55688cfa0ad2SJack F Vogel }
55698cfa0ad2SJack F Vogel
55708cfa0ad2SJack F Vogel dev_spec->kmrn_lock_loss_workaround_enabled = state;
55718cfa0ad2SJack F Vogel
55728cfa0ad2SJack F Vogel return;
55738cfa0ad2SJack F Vogel }
55748cfa0ad2SJack F Vogel
55758cfa0ad2SJack F Vogel /**
55768cfa0ad2SJack F Vogel * e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3
55778cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
55788cfa0ad2SJack F Vogel *
55798cfa0ad2SJack F Vogel * Workaround for 82566 power-down on D3 entry:
55808cfa0ad2SJack F Vogel * 1) disable gigabit link
55818cfa0ad2SJack F Vogel * 2) write VR power-down enable
55828cfa0ad2SJack F Vogel * 3) read it back
55838cfa0ad2SJack F Vogel * Continue if successful, else issue LCD reset and repeat
55848cfa0ad2SJack F Vogel **/
e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw * hw)55858cfa0ad2SJack F Vogel void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
55868cfa0ad2SJack F Vogel {
55878cfa0ad2SJack F Vogel u32 reg;
55888cfa0ad2SJack F Vogel u16 data;
55898cfa0ad2SJack F Vogel u8 retry = 0;
55908cfa0ad2SJack F Vogel
55918cfa0ad2SJack F Vogel DEBUGFUNC("e1000_igp3_phy_powerdown_workaround_ich8lan");
55928cfa0ad2SJack F Vogel
55938cfa0ad2SJack F Vogel if (hw->phy.type != e1000_phy_igp_3)
55946ab6bfe3SJack F Vogel return;
55958cfa0ad2SJack F Vogel
55968cfa0ad2SJack F Vogel /* Try the workaround twice (if needed) */
55978cfa0ad2SJack F Vogel do {
55988cfa0ad2SJack F Vogel /* Disable link */
55998cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_PHY_CTRL);
56008cfa0ad2SJack F Vogel reg |= (E1000_PHY_CTRL_GBE_DISABLE |
56018cfa0ad2SJack F Vogel E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
56028cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, reg);
56038cfa0ad2SJack F Vogel
56046ab6bfe3SJack F Vogel /* Call gig speed drop workaround on Gig disable before
56058cfa0ad2SJack F Vogel * accessing any PHY registers
56068cfa0ad2SJack F Vogel */
56078cfa0ad2SJack F Vogel if (hw->mac.type == e1000_ich8lan)
56088cfa0ad2SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw);
56098cfa0ad2SJack F Vogel
56108cfa0ad2SJack F Vogel /* Write VR power-down enable */
56118cfa0ad2SJack F Vogel hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data);
56128cfa0ad2SJack F Vogel data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
5613daf9197cSJack F Vogel hw->phy.ops.write_reg(hw, IGP3_VR_CTRL,
56148cfa0ad2SJack F Vogel data | IGP3_VR_CTRL_MODE_SHUTDOWN);
56158cfa0ad2SJack F Vogel
56168cfa0ad2SJack F Vogel /* Read it back and test */
56178cfa0ad2SJack F Vogel hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data);
56188cfa0ad2SJack F Vogel data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
56198cfa0ad2SJack F Vogel if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry)
56208cfa0ad2SJack F Vogel break;
56218cfa0ad2SJack F Vogel
56228cfa0ad2SJack F Vogel /* Issue PHY reset and repeat at most one more time */
56238cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_CTRL);
56248cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, reg | E1000_CTRL_PHY_RST);
56258cfa0ad2SJack F Vogel retry++;
56268cfa0ad2SJack F Vogel } while (retry);
56278cfa0ad2SJack F Vogel }
56288cfa0ad2SJack F Vogel
56298cfa0ad2SJack F Vogel /**
56308cfa0ad2SJack F Vogel * e1000_gig_downshift_workaround_ich8lan - WoL from S5 stops working
56318cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
56328cfa0ad2SJack F Vogel *
56338cfa0ad2SJack F Vogel * Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC),
56348cfa0ad2SJack F Vogel * LPLU, Gig disable, MDIC PHY reset):
56358cfa0ad2SJack F Vogel * 1) Set Kumeran Near-end loopback
56368cfa0ad2SJack F Vogel * 2) Clear Kumeran Near-end loopback
56374dab5c37SJack F Vogel * Should only be called for ICH8[m] devices with any 1G Phy.
56388cfa0ad2SJack F Vogel **/
e1000_gig_downshift_workaround_ich8lan(struct e1000_hw * hw)56398cfa0ad2SJack F Vogel void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
56408cfa0ad2SJack F Vogel {
56416ab6bfe3SJack F Vogel s32 ret_val;
5642089cdb39SAndrzej Ostruszka u16 reg_data = 0;
56438cfa0ad2SJack F Vogel
56448cfa0ad2SJack F Vogel DEBUGFUNC("e1000_gig_downshift_workaround_ich8lan");
56458cfa0ad2SJack F Vogel
56468cfa0ad2SJack F Vogel if ((hw->mac.type != e1000_ich8lan) ||
56474dab5c37SJack F Vogel (hw->phy.type == e1000_phy_ife))
56486ab6bfe3SJack F Vogel return;
56498cfa0ad2SJack F Vogel
56508cfa0ad2SJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
56518cfa0ad2SJack F Vogel ®_data);
56528cfa0ad2SJack F Vogel if (ret_val)
56536ab6bfe3SJack F Vogel return;
56548cfa0ad2SJack F Vogel reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK;
56558cfa0ad2SJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw,
56568cfa0ad2SJack F Vogel E1000_KMRNCTRLSTA_DIAG_OFFSET,
56578cfa0ad2SJack F Vogel reg_data);
56588cfa0ad2SJack F Vogel if (ret_val)
56598cfa0ad2SJack F Vogel return;
56606ab6bfe3SJack F Vogel reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK;
56616ab6bfe3SJack F Vogel e1000_write_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
56626ab6bfe3SJack F Vogel reg_data);
56638cfa0ad2SJack F Vogel }
56648cfa0ad2SJack F Vogel
56658cfa0ad2SJack F Vogel /**
56664dab5c37SJack F Vogel * e1000_suspend_workarounds_ich8lan - workarounds needed during S0->Sx
56678cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
56688cfa0ad2SJack F Vogel *
56698cfa0ad2SJack F Vogel * During S0 to Sx transition, it is possible the link remains at gig
56708cfa0ad2SJack F Vogel * instead of negotiating to a lower speed. Before going to Sx, set
56714dab5c37SJack F Vogel * 'Gig Disable' to force link speed negotiation to a lower speed based on
56724dab5c37SJack F Vogel * the LPLU setting in the NVM or custom setting. For PCH and newer parts,
56734dab5c37SJack F Vogel * the OEM bits PHY register (LED, GbE disable and LPLU configurations) also
56744dab5c37SJack F Vogel * needs to be written.
56756ab6bfe3SJack F Vogel * Parts that support (and are linked to a partner which support) EEE in
56766ab6bfe3SJack F Vogel * 100Mbps should disable LPLU since 100Mbps w/ EEE requires less power
56776ab6bfe3SJack F Vogel * than 10Mbps w/o EEE.
56788cfa0ad2SJack F Vogel **/
e1000_suspend_workarounds_ich8lan(struct e1000_hw * hw)56794dab5c37SJack F Vogel void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw)
56808cfa0ad2SJack F Vogel {
56816ab6bfe3SJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
56828cfa0ad2SJack F Vogel u32 phy_ctrl;
56837d9119bdSJack F Vogel s32 ret_val;
56848cfa0ad2SJack F Vogel
56854dab5c37SJack F Vogel DEBUGFUNC("e1000_suspend_workarounds_ich8lan");
56867d9119bdSJack F Vogel
56878cfa0ad2SJack F Vogel phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
56884dab5c37SJack F Vogel phy_ctrl |= E1000_PHY_CTRL_GBE_DISABLE;
56896ab6bfe3SJack F Vogel
56906ab6bfe3SJack F Vogel if (hw->phy.type == e1000_phy_i217) {
56916ab6bfe3SJack F Vogel u16 phy_reg, device_id = hw->device_id;
56926ab6bfe3SJack F Vogel
56936ab6bfe3SJack F Vogel if ((device_id == E1000_DEV_ID_PCH_LPTLP_I218_LM) ||
56948cc64f1eSJack F Vogel (device_id == E1000_DEV_ID_PCH_LPTLP_I218_V) ||
56958cc64f1eSJack F Vogel (device_id == E1000_DEV_ID_PCH_I218_LM3) ||
5696c80429ceSEric Joyner (device_id == E1000_DEV_ID_PCH_I218_V3) ||
5697295df609SEric Joyner (hw->mac.type >= e1000_pch_spt)) {
56986ab6bfe3SJack F Vogel u32 fextnvm6 = E1000_READ_REG(hw, E1000_FEXTNVM6);
56996ab6bfe3SJack F Vogel
57006ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM6,
57016ab6bfe3SJack F Vogel fextnvm6 & ~E1000_FEXTNVM6_REQ_PLL_CLK);
57026ab6bfe3SJack F Vogel }
57036ab6bfe3SJack F Vogel
57046ab6bfe3SJack F Vogel ret_val = hw->phy.ops.acquire(hw);
57056ab6bfe3SJack F Vogel if (ret_val)
57066ab6bfe3SJack F Vogel goto out;
57076ab6bfe3SJack F Vogel
57086ab6bfe3SJack F Vogel if (!dev_spec->eee_disable) {
57096ab6bfe3SJack F Vogel u16 eee_advert;
57106ab6bfe3SJack F Vogel
57116ab6bfe3SJack F Vogel ret_val =
57126ab6bfe3SJack F Vogel e1000_read_emi_reg_locked(hw,
57136ab6bfe3SJack F Vogel I217_EEE_ADVERTISEMENT,
57146ab6bfe3SJack F Vogel &eee_advert);
57156ab6bfe3SJack F Vogel if (ret_val)
57166ab6bfe3SJack F Vogel goto release;
57176ab6bfe3SJack F Vogel
57186ab6bfe3SJack F Vogel /* Disable LPLU if both link partners support 100BaseT
57196ab6bfe3SJack F Vogel * EEE and 100Full is advertised on both ends of the
57207609433eSJack F Vogel * link, and enable Auto Enable LPI since there will
57217609433eSJack F Vogel * be no driver to enable LPI while in Sx.
57226ab6bfe3SJack F Vogel */
57236ab6bfe3SJack F Vogel if ((eee_advert & I82579_EEE_100_SUPPORTED) &&
57246ab6bfe3SJack F Vogel (dev_spec->eee_lp_ability &
57256ab6bfe3SJack F Vogel I82579_EEE_100_SUPPORTED) &&
57267609433eSJack F Vogel (hw->phy.autoneg_advertised & ADVERTISE_100_FULL)) {
57276ab6bfe3SJack F Vogel phy_ctrl &= ~(E1000_PHY_CTRL_D0A_LPLU |
57286ab6bfe3SJack F Vogel E1000_PHY_CTRL_NOND0A_LPLU);
57297609433eSJack F Vogel
57307609433eSJack F Vogel /* Set Auto Enable LPI after link up */
57317609433eSJack F Vogel hw->phy.ops.read_reg_locked(hw,
57327609433eSJack F Vogel I217_LPI_GPIO_CTRL,
57337609433eSJack F Vogel &phy_reg);
57347609433eSJack F Vogel phy_reg |= I217_LPI_GPIO_CTRL_AUTO_EN_LPI;
57357609433eSJack F Vogel hw->phy.ops.write_reg_locked(hw,
57367609433eSJack F Vogel I217_LPI_GPIO_CTRL,
57377609433eSJack F Vogel phy_reg);
57387609433eSJack F Vogel }
57396ab6bfe3SJack F Vogel }
57406ab6bfe3SJack F Vogel
57416ab6bfe3SJack F Vogel /* For i217 Intel Rapid Start Technology support,
57426ab6bfe3SJack F Vogel * when the system is going into Sx and no manageability engine
57436ab6bfe3SJack F Vogel * is present, the driver must configure proxy to reset only on
57446ab6bfe3SJack F Vogel * power good. LPI (Low Power Idle) state must also reset only
57456ab6bfe3SJack F Vogel * on power good, as well as the MTA (Multicast table array).
57466ab6bfe3SJack F Vogel * The SMBus release must also be disabled on LCD reset.
57476ab6bfe3SJack F Vogel */
57486ab6bfe3SJack F Vogel if (!(E1000_READ_REG(hw, E1000_FWSM) &
57496ab6bfe3SJack F Vogel E1000_ICH_FWSM_FW_VALID)) {
57506ab6bfe3SJack F Vogel /* Enable proxy to reset only on power good. */
57516ab6bfe3SJack F Vogel hw->phy.ops.read_reg_locked(hw, I217_PROXY_CTRL,
57526ab6bfe3SJack F Vogel &phy_reg);
57536ab6bfe3SJack F Vogel phy_reg |= I217_PROXY_CTRL_AUTO_DISABLE;
57546ab6bfe3SJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_PROXY_CTRL,
57556ab6bfe3SJack F Vogel phy_reg);
57566ab6bfe3SJack F Vogel
57576ab6bfe3SJack F Vogel /* Set bit enable LPI (EEE) to reset only on
57586ab6bfe3SJack F Vogel * power good.
57596ab6bfe3SJack F Vogel */
57606ab6bfe3SJack F Vogel hw->phy.ops.read_reg_locked(hw, I217_SxCTRL, &phy_reg);
57616ab6bfe3SJack F Vogel phy_reg |= I217_SxCTRL_ENABLE_LPI_RESET;
57626ab6bfe3SJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_SxCTRL, phy_reg);
57636ab6bfe3SJack F Vogel
57646ab6bfe3SJack F Vogel /* Disable the SMB release on LCD reset. */
57656ab6bfe3SJack F Vogel hw->phy.ops.read_reg_locked(hw, I217_MEMPWR, &phy_reg);
57666ab6bfe3SJack F Vogel phy_reg &= ~I217_MEMPWR_DISABLE_SMB_RELEASE;
57676ab6bfe3SJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_MEMPWR, phy_reg);
57686ab6bfe3SJack F Vogel }
57696ab6bfe3SJack F Vogel
57706ab6bfe3SJack F Vogel /* Enable MTA to reset for Intel Rapid Start Technology
57716ab6bfe3SJack F Vogel * Support
57726ab6bfe3SJack F Vogel */
57736ab6bfe3SJack F Vogel hw->phy.ops.read_reg_locked(hw, I217_CGFREG, &phy_reg);
57746ab6bfe3SJack F Vogel phy_reg |= I217_CGFREG_ENABLE_MTA_RESET;
57756ab6bfe3SJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_CGFREG, phy_reg);
57766ab6bfe3SJack F Vogel
57776ab6bfe3SJack F Vogel release:
57786ab6bfe3SJack F Vogel hw->phy.ops.release(hw);
57796ab6bfe3SJack F Vogel }
57806ab6bfe3SJack F Vogel out:
57818cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
57826ab6bfe3SJack F Vogel
57834dab5c37SJack F Vogel if (hw->mac.type == e1000_ich8lan)
57844dab5c37SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw);
57859d81738fSJack F Vogel
57867d9119bdSJack F Vogel if (hw->mac.type >= e1000_pchlan) {
57871bbdc25fSKevin Bowling e1000_oem_bits_config_ich8lan(hw, false);
57886ab6bfe3SJack F Vogel
57896ab6bfe3SJack F Vogel /* Reset PHY to activate OEM bits on 82577/8 */
57906ab6bfe3SJack F Vogel if (hw->mac.type == e1000_pchlan)
57916ab6bfe3SJack F Vogel e1000_phy_hw_reset_generic(hw);
57926ab6bfe3SJack F Vogel
57937d9119bdSJack F Vogel ret_val = hw->phy.ops.acquire(hw);
57947d9119bdSJack F Vogel if (ret_val)
57957d9119bdSJack F Vogel return;
57967d9119bdSJack F Vogel e1000_write_smbus_addr(hw);
57977d9119bdSJack F Vogel hw->phy.ops.release(hw);
57988cfa0ad2SJack F Vogel }
57998cfa0ad2SJack F Vogel
58008cfa0ad2SJack F Vogel return;
58018cfa0ad2SJack F Vogel }
58028cfa0ad2SJack F Vogel
58038cfa0ad2SJack F Vogel /**
58044dab5c37SJack F Vogel * e1000_resume_workarounds_pchlan - workarounds needed during Sx->S0
58054dab5c37SJack F Vogel * @hw: pointer to the HW structure
58064dab5c37SJack F Vogel *
58074dab5c37SJack F Vogel * During Sx to S0 transitions on non-managed devices or managed devices
58084dab5c37SJack F Vogel * on which PHY resets are not blocked, if the PHY registers cannot be
58094dab5c37SJack F Vogel * accessed properly by the s/w toggle the LANPHYPC value to power cycle
58104dab5c37SJack F Vogel * the PHY.
58116ab6bfe3SJack F Vogel * On i217, setup Intel Rapid Start Technology.
58124dab5c37SJack F Vogel **/
e1000_resume_workarounds_pchlan(struct e1000_hw * hw)5813c80429ceSEric Joyner u32 e1000_resume_workarounds_pchlan(struct e1000_hw *hw)
58144dab5c37SJack F Vogel {
58154dab5c37SJack F Vogel s32 ret_val;
58164dab5c37SJack F Vogel
58174dab5c37SJack F Vogel DEBUGFUNC("e1000_resume_workarounds_pchlan");
58186ab6bfe3SJack F Vogel if (hw->mac.type < e1000_pch2lan)
5819c80429ceSEric Joyner return E1000_SUCCESS;
58204dab5c37SJack F Vogel
58216ab6bfe3SJack F Vogel ret_val = e1000_init_phy_workarounds_pchlan(hw);
58224dab5c37SJack F Vogel if (ret_val) {
58236ab6bfe3SJack F Vogel DEBUGOUT1("Failed to init PHY flow ret_val=%d\n", ret_val);
5824c80429ceSEric Joyner return ret_val;
58254dab5c37SJack F Vogel }
58264dab5c37SJack F Vogel
58276ab6bfe3SJack F Vogel /* For i217 Intel Rapid Start Technology support when the system
58286ab6bfe3SJack F Vogel * is transitioning from Sx and no manageability engine is present
58296ab6bfe3SJack F Vogel * configure SMBus to restore on reset, disable proxy, and enable
58306ab6bfe3SJack F Vogel * the reset on MTA (Multicast table array).
58316ab6bfe3SJack F Vogel */
58326ab6bfe3SJack F Vogel if (hw->phy.type == e1000_phy_i217) {
58336ab6bfe3SJack F Vogel u16 phy_reg;
58344dab5c37SJack F Vogel
58356ab6bfe3SJack F Vogel ret_val = hw->phy.ops.acquire(hw);
58366ab6bfe3SJack F Vogel if (ret_val) {
58376ab6bfe3SJack F Vogel DEBUGOUT("Failed to setup iRST\n");
5838c80429ceSEric Joyner return ret_val;
58396ab6bfe3SJack F Vogel }
58404dab5c37SJack F Vogel
58417609433eSJack F Vogel /* Clear Auto Enable LPI after link up */
58427609433eSJack F Vogel hw->phy.ops.read_reg_locked(hw, I217_LPI_GPIO_CTRL, &phy_reg);
58437609433eSJack F Vogel phy_reg &= ~I217_LPI_GPIO_CTRL_AUTO_EN_LPI;
58447609433eSJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_LPI_GPIO_CTRL, phy_reg);
58457609433eSJack F Vogel
58466ab6bfe3SJack F Vogel if (!(E1000_READ_REG(hw, E1000_FWSM) &
58476ab6bfe3SJack F Vogel E1000_ICH_FWSM_FW_VALID)) {
58486ab6bfe3SJack F Vogel /* Restore clear on SMB if no manageability engine
58496ab6bfe3SJack F Vogel * is present
58506ab6bfe3SJack F Vogel */
58516ab6bfe3SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, I217_MEMPWR,
58526ab6bfe3SJack F Vogel &phy_reg);
58536ab6bfe3SJack F Vogel if (ret_val)
58546ab6bfe3SJack F Vogel goto release;
58556ab6bfe3SJack F Vogel phy_reg |= I217_MEMPWR_DISABLE_SMB_RELEASE;
58566ab6bfe3SJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_MEMPWR, phy_reg);
58576ab6bfe3SJack F Vogel
58586ab6bfe3SJack F Vogel /* Disable Proxy */
58596ab6bfe3SJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_PROXY_CTRL, 0);
58606ab6bfe3SJack F Vogel }
58616ab6bfe3SJack F Vogel /* Enable reset on MTA */
58626ab6bfe3SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, I217_CGFREG,
58636ab6bfe3SJack F Vogel &phy_reg);
58646ab6bfe3SJack F Vogel if (ret_val)
58656ab6bfe3SJack F Vogel goto release;
58666ab6bfe3SJack F Vogel phy_reg &= ~I217_CGFREG_ENABLE_MTA_RESET;
58676ab6bfe3SJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_CGFREG, phy_reg);
58684dab5c37SJack F Vogel release:
58696ab6bfe3SJack F Vogel if (ret_val)
58706ab6bfe3SJack F Vogel DEBUGOUT1("Error %d in resume workarounds\n", ret_val);
58714dab5c37SJack F Vogel hw->phy.ops.release(hw);
5872c80429ceSEric Joyner return ret_val;
58736ab6bfe3SJack F Vogel }
5874c80429ceSEric Joyner return E1000_SUCCESS;
58754dab5c37SJack F Vogel }
58764dab5c37SJack F Vogel
58774dab5c37SJack F Vogel /**
58788cfa0ad2SJack F Vogel * e1000_cleanup_led_ich8lan - Restore the default LED operation
58798cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
58808cfa0ad2SJack F Vogel *
58818cfa0ad2SJack F Vogel * Return the LED back to the default configuration.
58828cfa0ad2SJack F Vogel **/
e1000_cleanup_led_ich8lan(struct e1000_hw * hw)58838cfa0ad2SJack F Vogel static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw)
58848cfa0ad2SJack F Vogel {
58858cfa0ad2SJack F Vogel DEBUGFUNC("e1000_cleanup_led_ich8lan");
58868cfa0ad2SJack F Vogel
58878cfa0ad2SJack F Vogel if (hw->phy.type == e1000_phy_ife)
5888a69ed8dfSJack F Vogel return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
58898cfa0ad2SJack F Vogel 0);
58908cfa0ad2SJack F Vogel
5891a69ed8dfSJack F Vogel E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
5892a69ed8dfSJack F Vogel return E1000_SUCCESS;
58938cfa0ad2SJack F Vogel }
58948cfa0ad2SJack F Vogel
58958cfa0ad2SJack F Vogel /**
58968cfa0ad2SJack F Vogel * e1000_led_on_ich8lan - Turn LEDs on
58978cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
58988cfa0ad2SJack F Vogel *
58998cfa0ad2SJack F Vogel * Turn on the LEDs.
59008cfa0ad2SJack F Vogel **/
e1000_led_on_ich8lan(struct e1000_hw * hw)59018cfa0ad2SJack F Vogel static s32 e1000_led_on_ich8lan(struct e1000_hw *hw)
59028cfa0ad2SJack F Vogel {
59038cfa0ad2SJack F Vogel DEBUGFUNC("e1000_led_on_ich8lan");
59048cfa0ad2SJack F Vogel
59058cfa0ad2SJack F Vogel if (hw->phy.type == e1000_phy_ife)
5906a69ed8dfSJack F Vogel return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
59078cfa0ad2SJack F Vogel (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON));
59088cfa0ad2SJack F Vogel
5909a69ed8dfSJack F Vogel E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2);
5910a69ed8dfSJack F Vogel return E1000_SUCCESS;
59118cfa0ad2SJack F Vogel }
59128cfa0ad2SJack F Vogel
59138cfa0ad2SJack F Vogel /**
59148cfa0ad2SJack F Vogel * e1000_led_off_ich8lan - Turn LEDs off
59158cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
59168cfa0ad2SJack F Vogel *
59178cfa0ad2SJack F Vogel * Turn off the LEDs.
59188cfa0ad2SJack F Vogel **/
e1000_led_off_ich8lan(struct e1000_hw * hw)59198cfa0ad2SJack F Vogel static s32 e1000_led_off_ich8lan(struct e1000_hw *hw)
59208cfa0ad2SJack F Vogel {
59218cfa0ad2SJack F Vogel DEBUGFUNC("e1000_led_off_ich8lan");
59228cfa0ad2SJack F Vogel
59238cfa0ad2SJack F Vogel if (hw->phy.type == e1000_phy_ife)
5924a69ed8dfSJack F Vogel return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
59258cfa0ad2SJack F Vogel (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF));
59268cfa0ad2SJack F Vogel
5927a69ed8dfSJack F Vogel E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
5928a69ed8dfSJack F Vogel return E1000_SUCCESS;
59298cfa0ad2SJack F Vogel }
59308cfa0ad2SJack F Vogel
59318cfa0ad2SJack F Vogel /**
59329d81738fSJack F Vogel * e1000_setup_led_pchlan - Configures SW controllable LED
59339d81738fSJack F Vogel * @hw: pointer to the HW structure
59349d81738fSJack F Vogel *
59359d81738fSJack F Vogel * This prepares the SW controllable LED for use.
59369d81738fSJack F Vogel **/
e1000_setup_led_pchlan(struct e1000_hw * hw)59379d81738fSJack F Vogel static s32 e1000_setup_led_pchlan(struct e1000_hw *hw)
59389d81738fSJack F Vogel {
59399d81738fSJack F Vogel DEBUGFUNC("e1000_setup_led_pchlan");
59409d81738fSJack F Vogel
59419d81738fSJack F Vogel return hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
59429d81738fSJack F Vogel (u16)hw->mac.ledctl_mode1);
59439d81738fSJack F Vogel }
59449d81738fSJack F Vogel
59459d81738fSJack F Vogel /**
59469d81738fSJack F Vogel * e1000_cleanup_led_pchlan - Restore the default LED operation
59479d81738fSJack F Vogel * @hw: pointer to the HW structure
59489d81738fSJack F Vogel *
59499d81738fSJack F Vogel * Return the LED back to the default configuration.
59509d81738fSJack F Vogel **/
e1000_cleanup_led_pchlan(struct e1000_hw * hw)59519d81738fSJack F Vogel static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw)
59529d81738fSJack F Vogel {
59539d81738fSJack F Vogel DEBUGFUNC("e1000_cleanup_led_pchlan");
59549d81738fSJack F Vogel
59559d81738fSJack F Vogel return hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
59569d81738fSJack F Vogel (u16)hw->mac.ledctl_default);
59579d81738fSJack F Vogel }
59589d81738fSJack F Vogel
59599d81738fSJack F Vogel /**
59609d81738fSJack F Vogel * e1000_led_on_pchlan - Turn LEDs on
59619d81738fSJack F Vogel * @hw: pointer to the HW structure
59629d81738fSJack F Vogel *
59639d81738fSJack F Vogel * Turn on the LEDs.
59649d81738fSJack F Vogel **/
e1000_led_on_pchlan(struct e1000_hw * hw)59659d81738fSJack F Vogel static s32 e1000_led_on_pchlan(struct e1000_hw *hw)
59669d81738fSJack F Vogel {
59679d81738fSJack F Vogel u16 data = (u16)hw->mac.ledctl_mode2;
59689d81738fSJack F Vogel u32 i, led;
59699d81738fSJack F Vogel
59709d81738fSJack F Vogel DEBUGFUNC("e1000_led_on_pchlan");
59719d81738fSJack F Vogel
59726ab6bfe3SJack F Vogel /* If no link, then turn LED on by setting the invert bit
59739d81738fSJack F Vogel * for each LED that's mode is "link_up" in ledctl_mode2.
59749d81738fSJack F Vogel */
59759d81738fSJack F Vogel if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
59769d81738fSJack F Vogel for (i = 0; i < 3; i++) {
59779d81738fSJack F Vogel led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
59789d81738fSJack F Vogel if ((led & E1000_PHY_LED0_MODE_MASK) !=
59799d81738fSJack F Vogel E1000_LEDCTL_MODE_LINK_UP)
59809d81738fSJack F Vogel continue;
59819d81738fSJack F Vogel if (led & E1000_PHY_LED0_IVRT)
59829d81738fSJack F Vogel data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
59839d81738fSJack F Vogel else
59849d81738fSJack F Vogel data |= (E1000_PHY_LED0_IVRT << (i * 5));
59859d81738fSJack F Vogel }
59869d81738fSJack F Vogel }
59879d81738fSJack F Vogel
59889d81738fSJack F Vogel return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data);
59899d81738fSJack F Vogel }
59909d81738fSJack F Vogel
59919d81738fSJack F Vogel /**
59929d81738fSJack F Vogel * e1000_led_off_pchlan - Turn LEDs off
59939d81738fSJack F Vogel * @hw: pointer to the HW structure
59949d81738fSJack F Vogel *
59959d81738fSJack F Vogel * Turn off the LEDs.
59969d81738fSJack F Vogel **/
e1000_led_off_pchlan(struct e1000_hw * hw)59979d81738fSJack F Vogel static s32 e1000_led_off_pchlan(struct e1000_hw *hw)
59989d81738fSJack F Vogel {
59999d81738fSJack F Vogel u16 data = (u16)hw->mac.ledctl_mode1;
60009d81738fSJack F Vogel u32 i, led;
60019d81738fSJack F Vogel
60029d81738fSJack F Vogel DEBUGFUNC("e1000_led_off_pchlan");
60039d81738fSJack F Vogel
60046ab6bfe3SJack F Vogel /* If no link, then turn LED off by clearing the invert bit
60059d81738fSJack F Vogel * for each LED that's mode is "link_up" in ledctl_mode1.
60069d81738fSJack F Vogel */
60079d81738fSJack F Vogel if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
60089d81738fSJack F Vogel for (i = 0; i < 3; i++) {
60099d81738fSJack F Vogel led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
60109d81738fSJack F Vogel if ((led & E1000_PHY_LED0_MODE_MASK) !=
60119d81738fSJack F Vogel E1000_LEDCTL_MODE_LINK_UP)
60129d81738fSJack F Vogel continue;
60139d81738fSJack F Vogel if (led & E1000_PHY_LED0_IVRT)
60149d81738fSJack F Vogel data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
60159d81738fSJack F Vogel else
60169d81738fSJack F Vogel data |= (E1000_PHY_LED0_IVRT << (i * 5));
60179d81738fSJack F Vogel }
60189d81738fSJack F Vogel }
60199d81738fSJack F Vogel
60209d81738fSJack F Vogel return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data);
60219d81738fSJack F Vogel }
60229d81738fSJack F Vogel
60239d81738fSJack F Vogel /**
60247d9119bdSJack F Vogel * e1000_get_cfg_done_ich8lan - Read config done bit after Full or PHY reset
60258cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
60268cfa0ad2SJack F Vogel *
60277d9119bdSJack F Vogel * Read appropriate register for the config done bit for completion status
60287d9119bdSJack F Vogel * and configure the PHY through s/w for EEPROM-less parts.
60297d9119bdSJack F Vogel *
60307d9119bdSJack F Vogel * NOTE: some silicon which is EEPROM-less will fail trying to read the
60317d9119bdSJack F Vogel * config done bit, so only an error is logged and continues. If we were
60327d9119bdSJack F Vogel * to return with error, EEPROM-less silicon would not be able to be reset
60337d9119bdSJack F Vogel * or change link.
60348cfa0ad2SJack F Vogel **/
e1000_get_cfg_done_ich8lan(struct e1000_hw * hw)60358cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
60368cfa0ad2SJack F Vogel {
60378cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS;
60388cfa0ad2SJack F Vogel u32 bank = 0;
60397d9119bdSJack F Vogel u32 status;
60408cfa0ad2SJack F Vogel
60417d9119bdSJack F Vogel DEBUGFUNC("e1000_get_cfg_done_ich8lan");
60429d81738fSJack F Vogel
60438cfa0ad2SJack F Vogel e1000_get_cfg_done_generic(hw);
60448cfa0ad2SJack F Vogel
60457d9119bdSJack F Vogel /* Wait for indication from h/w that it has completed basic config */
60467d9119bdSJack F Vogel if (hw->mac.type >= e1000_ich10lan) {
60477d9119bdSJack F Vogel e1000_lan_init_done_ich8lan(hw);
60487d9119bdSJack F Vogel } else {
60497d9119bdSJack F Vogel ret_val = e1000_get_auto_rd_done_generic(hw);
60507d9119bdSJack F Vogel if (ret_val) {
60516ab6bfe3SJack F Vogel /* When auto config read does not complete, do not
60527d9119bdSJack F Vogel * return with an error. This can happen in situations
60537d9119bdSJack F Vogel * where there is no eeprom and prevents getting link.
60547d9119bdSJack F Vogel */
60557d9119bdSJack F Vogel DEBUGOUT("Auto Read Done did not complete\n");
60567d9119bdSJack F Vogel ret_val = E1000_SUCCESS;
60577d9119bdSJack F Vogel }
60587d9119bdSJack F Vogel }
60597d9119bdSJack F Vogel
60607d9119bdSJack F Vogel /* Clear PHY Reset Asserted bit */
60617d9119bdSJack F Vogel status = E1000_READ_REG(hw, E1000_STATUS);
60627d9119bdSJack F Vogel if (status & E1000_STATUS_PHYRA)
60637d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_STATUS, status & ~E1000_STATUS_PHYRA);
60647d9119bdSJack F Vogel else
60657d9119bdSJack F Vogel DEBUGOUT("PHY Reset Asserted not set - needs delay\n");
60667d9119bdSJack F Vogel
60678cfa0ad2SJack F Vogel /* If EEPROM is not marked present, init the IGP 3 PHY manually */
60684edd8523SJack F Vogel if (hw->mac.type <= e1000_ich9lan) {
60696ab6bfe3SJack F Vogel if (!(E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) &&
60708cfa0ad2SJack F Vogel (hw->phy.type == e1000_phy_igp_3)) {
60718cfa0ad2SJack F Vogel e1000_phy_init_script_igp3(hw);
60728cfa0ad2SJack F Vogel }
60738cfa0ad2SJack F Vogel } else {
60748cfa0ad2SJack F Vogel if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) {
6075daf9197cSJack F Vogel /* Maybe we should do a basic PHY config */
60768cfa0ad2SJack F Vogel DEBUGOUT("EEPROM not present\n");
60778cfa0ad2SJack F Vogel ret_val = -E1000_ERR_CONFIG;
60788cfa0ad2SJack F Vogel }
60798cfa0ad2SJack F Vogel }
60808cfa0ad2SJack F Vogel
60818cfa0ad2SJack F Vogel return ret_val;
60828cfa0ad2SJack F Vogel }
60838cfa0ad2SJack F Vogel
60848cfa0ad2SJack F Vogel /**
60858cfa0ad2SJack F Vogel * e1000_power_down_phy_copper_ich8lan - Remove link during PHY power down
60868cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
60878cfa0ad2SJack F Vogel *
60888cfa0ad2SJack F Vogel * In the case of a PHY power down to save power, or to turn off link during a
60898cfa0ad2SJack F Vogel * driver unload, or wake on lan is not enabled, remove the link.
60908cfa0ad2SJack F Vogel **/
e1000_power_down_phy_copper_ich8lan(struct e1000_hw * hw)60918cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw)
60928cfa0ad2SJack F Vogel {
60938cfa0ad2SJack F Vogel /* If the management interface is not enabled, then power down */
6094daf9197cSJack F Vogel if (!(hw->mac.ops.check_mng_mode(hw) ||
6095daf9197cSJack F Vogel hw->phy.ops.check_reset_block(hw)))
60968cfa0ad2SJack F Vogel e1000_power_down_phy_copper(hw);
60978cfa0ad2SJack F Vogel
60988cfa0ad2SJack F Vogel return;
60998cfa0ad2SJack F Vogel }
61008cfa0ad2SJack F Vogel
61018cfa0ad2SJack F Vogel /**
61028cfa0ad2SJack F Vogel * e1000_clear_hw_cntrs_ich8lan - Clear statistical counters
61038cfa0ad2SJack F Vogel * @hw: pointer to the HW structure
61048cfa0ad2SJack F Vogel *
61058cfa0ad2SJack F Vogel * Clears hardware counters specific to the silicon family and calls
61068cfa0ad2SJack F Vogel * clear_hw_cntrs_generic to clear all general purpose counters.
61078cfa0ad2SJack F Vogel **/
e1000_clear_hw_cntrs_ich8lan(struct e1000_hw * hw)61088cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
61098cfa0ad2SJack F Vogel {
61109d81738fSJack F Vogel u16 phy_data;
61114dab5c37SJack F Vogel s32 ret_val;
61129d81738fSJack F Vogel
61138cfa0ad2SJack F Vogel DEBUGFUNC("e1000_clear_hw_cntrs_ich8lan");
61148cfa0ad2SJack F Vogel
61158cfa0ad2SJack F Vogel e1000_clear_hw_cntrs_base_generic(hw);
61168cfa0ad2SJack F Vogel
6117daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_ALGNERRC);
6118daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_RXERRC);
6119daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_TNCRS);
6120daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_CEXTERR);
6121daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_TSCTC);
6122daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_TSCTFC);
61238cfa0ad2SJack F Vogel
6124daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_MGTPRC);
6125daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_MGTPDC);
6126daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_MGTPTC);
61278cfa0ad2SJack F Vogel
6128daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_IAC);
6129daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_ICRXOC);
61309d81738fSJack F Vogel
61319d81738fSJack F Vogel /* Clear PHY statistics registers */
61329d81738fSJack F Vogel if ((hw->phy.type == e1000_phy_82578) ||
61337d9119bdSJack F Vogel (hw->phy.type == e1000_phy_82579) ||
61346ab6bfe3SJack F Vogel (hw->phy.type == e1000_phy_i217) ||
61359d81738fSJack F Vogel (hw->phy.type == e1000_phy_82577)) {
61364dab5c37SJack F Vogel ret_val = hw->phy.ops.acquire(hw);
61374dab5c37SJack F Vogel if (ret_val)
61384dab5c37SJack F Vogel return;
61394dab5c37SJack F Vogel ret_val = hw->phy.ops.set_page(hw,
61404dab5c37SJack F Vogel HV_STATS_PAGE << IGP_PAGE_SHIFT);
61414dab5c37SJack F Vogel if (ret_val)
61424dab5c37SJack F Vogel goto release;
61434dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_SCC_UPPER, &phy_data);
61444dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_SCC_LOWER, &phy_data);
61454dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_ECOL_UPPER, &phy_data);
61464dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_ECOL_LOWER, &phy_data);
61474dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_MCC_UPPER, &phy_data);
61484dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_MCC_LOWER, &phy_data);
61494dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_LATECOL_UPPER, &phy_data);
61504dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_LATECOL_LOWER, &phy_data);
61514dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_COLC_UPPER, &phy_data);
61524dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_COLC_LOWER, &phy_data);
61534dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_DC_UPPER, &phy_data);
61544dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_DC_LOWER, &phy_data);
61554dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_TNCRS_UPPER, &phy_data);
61564dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_TNCRS_LOWER, &phy_data);
61574dab5c37SJack F Vogel release:
61584dab5c37SJack F Vogel hw->phy.ops.release(hw);
61599d81738fSJack F Vogel }
61608cfa0ad2SJack F Vogel }
61618cfa0ad2SJack F Vogel
6162d5ad2f2aSWenzhuo Lu /**
6163d5ad2f2aSWenzhuo Lu * e1000_configure_k0s_lpt - Configure K0s power state
6164d5ad2f2aSWenzhuo Lu * @hw: pointer to the HW structure
6165d5ad2f2aSWenzhuo Lu * @entry_latency: Tx idle period for entering K0s - valid values are 0 to 3.
6166d5ad2f2aSWenzhuo Lu * 0 corresponds to 128ns, each value over 0 doubles the duration.
6167d5ad2f2aSWenzhuo Lu * @min_time: Minimum Tx idle period allowed - valid values are 0 to 4.
6168d5ad2f2aSWenzhuo Lu * 0 corresponds to 128ns, each value over 0 doubles the duration.
6169d5ad2f2aSWenzhuo Lu *
6170d5ad2f2aSWenzhuo Lu * Configure the K1 power state based on the provided parameter.
6171d5ad2f2aSWenzhuo Lu * Assumes semaphore already acquired.
6172d5ad2f2aSWenzhuo Lu *
6173d5ad2f2aSWenzhuo Lu * Success returns 0, Failure returns:
6174d5ad2f2aSWenzhuo Lu * -E1000_ERR_PHY (-2) in case of access error
6175d5ad2f2aSWenzhuo Lu * -E1000_ERR_PARAM (-4) in case of parameters error
6176d5ad2f2aSWenzhuo Lu **/
e1000_configure_k0s_lpt(struct e1000_hw * hw,u8 entry_latency,u8 min_time)6177d5ad2f2aSWenzhuo Lu s32 e1000_configure_k0s_lpt(struct e1000_hw *hw, u8 entry_latency, u8 min_time)
6178d5ad2f2aSWenzhuo Lu {
6179d5ad2f2aSWenzhuo Lu s32 ret_val;
6180d5ad2f2aSWenzhuo Lu u16 kmrn_reg = 0;
6181d5ad2f2aSWenzhuo Lu
6182d5ad2f2aSWenzhuo Lu DEBUGFUNC("e1000_configure_k0s_lpt");
6183d5ad2f2aSWenzhuo Lu
6184d5ad2f2aSWenzhuo Lu if (entry_latency > 3 || min_time > 4)
6185d5ad2f2aSWenzhuo Lu return -E1000_ERR_PARAM;
6186d5ad2f2aSWenzhuo Lu
6187d5ad2f2aSWenzhuo Lu ret_val = e1000_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K0S_CTRL,
6188d5ad2f2aSWenzhuo Lu &kmrn_reg);
6189d5ad2f2aSWenzhuo Lu if (ret_val)
6190d5ad2f2aSWenzhuo Lu return ret_val;
6191d5ad2f2aSWenzhuo Lu
6192d5ad2f2aSWenzhuo Lu /* for now don't touch the latency */
6193d5ad2f2aSWenzhuo Lu kmrn_reg &= ~(E1000_KMRNCTRLSTA_K0S_CTRL_MIN_TIME_MASK);
6194d5ad2f2aSWenzhuo Lu kmrn_reg |= ((min_time << E1000_KMRNCTRLSTA_K0S_CTRL_MIN_TIME_SHIFT));
6195d5ad2f2aSWenzhuo Lu
6196d5ad2f2aSWenzhuo Lu ret_val = e1000_write_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K0S_CTRL,
6197d5ad2f2aSWenzhuo Lu kmrn_reg);
6198d5ad2f2aSWenzhuo Lu if (ret_val)
6199d5ad2f2aSWenzhuo Lu return ret_val;
6200d5ad2f2aSWenzhuo Lu
6201d5ad2f2aSWenzhuo Lu return E1000_SUCCESS;
6202d5ad2f2aSWenzhuo Lu }
6203