18cfa0ad2SJack F Vogel /****************************************************************************** 27282444bSPedro F. Giffuni SPDX-License-Identifier: BSD-3-Clause 38cfa0ad2SJack F Vogel 4*fc7682b1SKevin 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 /*$FreeBSD$*/ 358cfa0ad2SJack F Vogel 366ab6bfe3SJack F Vogel /* 82562G 10/100 Network Connection 37daf9197cSJack F Vogel * 82562G-2 10/100 Network Connection 38daf9197cSJack F Vogel * 82562GT 10/100 Network Connection 39daf9197cSJack F Vogel * 82562GT-2 10/100 Network Connection 40daf9197cSJack F Vogel * 82562V 10/100 Network Connection 41daf9197cSJack F Vogel * 82562V-2 10/100 Network Connection 42daf9197cSJack F Vogel * 82566DC-2 Gigabit Network Connection 43daf9197cSJack F Vogel * 82566DC Gigabit Network Connection 44daf9197cSJack F Vogel * 82566DM-2 Gigabit Network Connection 45daf9197cSJack F Vogel * 82566DM Gigabit Network Connection 46daf9197cSJack F Vogel * 82566MC Gigabit Network Connection 47daf9197cSJack F Vogel * 82566MM Gigabit Network Connection 48daf9197cSJack F Vogel * 82567LM Gigabit Network Connection 49daf9197cSJack F Vogel * 82567LF Gigabit Network Connection 50daf9197cSJack F Vogel * 82567V Gigabit Network Connection 51daf9197cSJack F Vogel * 82567LM-2 Gigabit Network Connection 52daf9197cSJack F Vogel * 82567LF-2 Gigabit Network Connection 53daf9197cSJack F Vogel * 82567V-2 Gigabit Network Connection 54daf9197cSJack F Vogel * 82567LF-3 Gigabit Network Connection 55daf9197cSJack F Vogel * 82567LM-3 Gigabit Network Connection 56daf9197cSJack F Vogel * 82567LM-4 Gigabit Network Connection 579d81738fSJack F Vogel * 82577LM Gigabit Network Connection 589d81738fSJack F Vogel * 82577LC Gigabit Network Connection 599d81738fSJack F Vogel * 82578DM Gigabit Network Connection 609d81738fSJack F Vogel * 82578DC Gigabit Network Connection 617d9119bdSJack F Vogel * 82579LM Gigabit Network Connection 627d9119bdSJack F Vogel * 82579V Gigabit Network Connection 637609433eSJack F Vogel * Ethernet Connection I217-LM 647609433eSJack F Vogel * Ethernet Connection I217-V 657609433eSJack F Vogel * Ethernet Connection I218-V 667609433eSJack F Vogel * Ethernet Connection I218-LM 678cc64f1eSJack F Vogel * Ethernet Connection (2) I218-LM 688cc64f1eSJack F Vogel * Ethernet Connection (2) I218-V 698cc64f1eSJack F Vogel * Ethernet Connection (3) I218-LM 708cc64f1eSJack F Vogel * Ethernet Connection (3) I218-V 718cfa0ad2SJack F Vogel */ 728cfa0ad2SJack F Vogel 738cfa0ad2SJack F Vogel #include "e1000_api.h" 748cfa0ad2SJack F Vogel 75*fc7682b1SKevin Bowling static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state); 768cfa0ad2SJack F Vogel static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw); 778cfa0ad2SJack F Vogel static void e1000_release_swflag_ich8lan(struct e1000_hw *hw); 784edd8523SJack F Vogel static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw); 794edd8523SJack F Vogel static void e1000_release_nvm_ich8lan(struct e1000_hw *hw); 808cfa0ad2SJack F Vogel static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw); 817d9119bdSJack F Vogel static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw); 828cc64f1eSJack F Vogel static int e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index); 838cc64f1eSJack F Vogel static int e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index); 847609433eSJack F Vogel static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw); 85730d3130SJack F Vogel static void e1000_update_mc_addr_list_pch2lan(struct e1000_hw *hw, 86730d3130SJack F Vogel u8 *mc_addr_list, 87730d3130SJack F Vogel u32 mc_addr_count); 888cfa0ad2SJack F Vogel static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw); 898cfa0ad2SJack F Vogel static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw); 904edd8523SJack F Vogel static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active); 918cfa0ad2SJack F Vogel static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, 928cfa0ad2SJack F Vogel bool active); 938cfa0ad2SJack F Vogel static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, 948cfa0ad2SJack F Vogel bool active); 958cfa0ad2SJack F Vogel static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, 968cfa0ad2SJack F Vogel u16 words, u16 *data); 97c80429ceSEric Joyner static s32 e1000_read_nvm_spt(struct e1000_hw *hw, u16 offset, u16 words, 98c80429ceSEric Joyner u16 *data); 998cfa0ad2SJack F Vogel static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, 1008cfa0ad2SJack F Vogel u16 words, u16 *data); 1018cfa0ad2SJack F Vogel static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw); 1028cfa0ad2SJack F Vogel static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw); 103c80429ceSEric Joyner static s32 e1000_update_nvm_checksum_spt(struct e1000_hw *hw); 1048cfa0ad2SJack F Vogel static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, 1058cfa0ad2SJack F Vogel u16 *data); 1069d81738fSJack F Vogel static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw); 1078cfa0ad2SJack F Vogel static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw); 1088cfa0ad2SJack F Vogel static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw); 1098cfa0ad2SJack F Vogel static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw); 1108cfa0ad2SJack F Vogel static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw); 1118cfa0ad2SJack F Vogel static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw); 1126ab6bfe3SJack F Vogel static s32 e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw); 1138cfa0ad2SJack F Vogel static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, 1148cfa0ad2SJack F Vogel u16 *speed, u16 *duplex); 1158cfa0ad2SJack F Vogel static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw); 1168cfa0ad2SJack F Vogel static s32 e1000_led_on_ich8lan(struct e1000_hw *hw); 1178cfa0ad2SJack F Vogel static s32 e1000_led_off_ich8lan(struct e1000_hw *hw); 1184edd8523SJack F Vogel static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link); 1199d81738fSJack F Vogel static s32 e1000_setup_led_pchlan(struct e1000_hw *hw); 1209d81738fSJack F Vogel static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw); 1219d81738fSJack F Vogel static s32 e1000_led_on_pchlan(struct e1000_hw *hw); 1229d81738fSJack F Vogel static s32 e1000_led_off_pchlan(struct e1000_hw *hw); 1238cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw); 1248cfa0ad2SJack F Vogel static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank); 1258cfa0ad2SJack F Vogel static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw); 1268cfa0ad2SJack F Vogel static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw); 1278cfa0ad2SJack F Vogel static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, 1288cfa0ad2SJack F Vogel u32 offset, u8 *data); 1298cfa0ad2SJack F Vogel static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, 1308cfa0ad2SJack F Vogel u8 size, u16 *data); 131c80429ceSEric Joyner static s32 e1000_read_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset, 132c80429ceSEric Joyner u32 *data); 133c80429ceSEric Joyner static s32 e1000_read_flash_dword_ich8lan(struct e1000_hw *hw, 134c80429ceSEric Joyner u32 offset, u32 *data); 135c80429ceSEric Joyner static s32 e1000_write_flash_data32_ich8lan(struct e1000_hw *hw, 136c80429ceSEric Joyner u32 offset, u32 data); 137c80429ceSEric Joyner static s32 e1000_retry_write_flash_dword_ich8lan(struct e1000_hw *hw, 138c80429ceSEric Joyner u32 offset, u32 dword); 1398cfa0ad2SJack F Vogel static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, 1408cfa0ad2SJack F Vogel u32 offset, u16 *data); 1418cfa0ad2SJack F Vogel static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, 1428cfa0ad2SJack F Vogel u32 offset, u8 byte); 1438cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw); 1448cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw); 1454edd8523SJack F Vogel static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw); 146a69ed8dfSJack F Vogel static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw); 1477d9119bdSJack F Vogel static s32 e1000_k1_workaround_lv(struct e1000_hw *hw); 1487d9119bdSJack F Vogel static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate); 149e373323fSSean Bruno static s32 e1000_set_obff_timer_pch_lpt(struct e1000_hw *hw, u32 itr); 1508cfa0ad2SJack F Vogel 1518cfa0ad2SJack F Vogel /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */ 1528cfa0ad2SJack F Vogel /* Offset 04h HSFSTS */ 1538cfa0ad2SJack F Vogel union ich8_hws_flash_status { 1548cfa0ad2SJack F Vogel struct ich8_hsfsts { 1558cfa0ad2SJack F Vogel u16 flcdone:1; /* bit 0 Flash Cycle Done */ 1568cfa0ad2SJack F Vogel u16 flcerr:1; /* bit 1 Flash Cycle Error */ 1578cfa0ad2SJack F Vogel u16 dael:1; /* bit 2 Direct Access error Log */ 1588cfa0ad2SJack F Vogel u16 berasesz:2; /* bit 4:3 Sector Erase Size */ 1598cfa0ad2SJack F Vogel u16 flcinprog:1; /* bit 5 flash cycle in Progress */ 1608cfa0ad2SJack F Vogel u16 reserved1:2; /* bit 13:6 Reserved */ 1618cfa0ad2SJack F Vogel u16 reserved2:6; /* bit 13:6 Reserved */ 1628cfa0ad2SJack F Vogel u16 fldesvalid:1; /* bit 14 Flash Descriptor Valid */ 1638cfa0ad2SJack F Vogel u16 flockdn:1; /* bit 15 Flash Config Lock-Down */ 1648cfa0ad2SJack F Vogel } hsf_status; 1658cfa0ad2SJack F Vogel u16 regval; 1668cfa0ad2SJack F Vogel }; 1678cfa0ad2SJack F Vogel 1688cfa0ad2SJack F Vogel /* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */ 1698cfa0ad2SJack F Vogel /* Offset 06h FLCTL */ 1708cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl { 1718cfa0ad2SJack F Vogel struct ich8_hsflctl { 1728cfa0ad2SJack F Vogel u16 flcgo:1; /* 0 Flash Cycle Go */ 1738cfa0ad2SJack F Vogel u16 flcycle:2; /* 2:1 Flash Cycle */ 1748cfa0ad2SJack F Vogel u16 reserved:5; /* 7:3 Reserved */ 1758cfa0ad2SJack F Vogel u16 fldbcount:2; /* 9:8 Flash Data Byte Count */ 1768cfa0ad2SJack F Vogel u16 flockdn:6; /* 15:10 Reserved */ 1778cfa0ad2SJack F Vogel } hsf_ctrl; 1788cfa0ad2SJack F Vogel u16 regval; 1798cfa0ad2SJack F Vogel }; 1808cfa0ad2SJack F Vogel 1818cfa0ad2SJack F Vogel /* ICH Flash Region Access Permissions */ 1828cfa0ad2SJack F Vogel union ich8_hws_flash_regacc { 1838cfa0ad2SJack F Vogel struct ich8_flracc { 1848cfa0ad2SJack F Vogel u32 grra:8; /* 0:7 GbE region Read Access */ 1858cfa0ad2SJack F Vogel u32 grwa:8; /* 8:15 GbE region Write Access */ 1868cfa0ad2SJack F Vogel u32 gmrag:8; /* 23:16 GbE Master Read Access Grant */ 1878cfa0ad2SJack F Vogel u32 gmwag:8; /* 31:24 GbE Master Write Access Grant */ 1888cfa0ad2SJack F Vogel } hsf_flregacc; 1898cfa0ad2SJack F Vogel u16 regval; 1908cfa0ad2SJack F Vogel }; 1918cfa0ad2SJack F Vogel 1926ab6bfe3SJack F Vogel /** 1936ab6bfe3SJack F Vogel * e1000_phy_is_accessible_pchlan - Check if able to access PHY registers 1946ab6bfe3SJack F Vogel * @hw: pointer to the HW structure 1956ab6bfe3SJack F Vogel * 1966ab6bfe3SJack F Vogel * Test access to the PHY registers by reading the PHY ID registers. If 1976ab6bfe3SJack F Vogel * the PHY ID is already known (e.g. resume path) compare it with known ID, 1986ab6bfe3SJack F Vogel * otherwise assume the read PHY ID is correct if it is valid. 1996ab6bfe3SJack F Vogel * 2006ab6bfe3SJack F Vogel * Assumes the sw/fw/hw semaphore is already acquired. 2016ab6bfe3SJack F Vogel **/ 2026ab6bfe3SJack F Vogel static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw) 2034dab5c37SJack F Vogel { 2046ab6bfe3SJack F Vogel u16 phy_reg = 0; 2056ab6bfe3SJack F Vogel u32 phy_id = 0; 2067609433eSJack F Vogel s32 ret_val = 0; 2076ab6bfe3SJack F Vogel u16 retry_count; 2087609433eSJack F Vogel u32 mac_reg = 0; 2094dab5c37SJack F Vogel 2106ab6bfe3SJack F Vogel for (retry_count = 0; retry_count < 2; retry_count++) { 2116ab6bfe3SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID1, &phy_reg); 2126ab6bfe3SJack F Vogel if (ret_val || (phy_reg == 0xFFFF)) 2136ab6bfe3SJack F Vogel continue; 2146ab6bfe3SJack F Vogel phy_id = (u32)(phy_reg << 16); 2154dab5c37SJack F Vogel 2166ab6bfe3SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID2, &phy_reg); 2176ab6bfe3SJack F Vogel if (ret_val || (phy_reg == 0xFFFF)) { 2186ab6bfe3SJack F Vogel phy_id = 0; 2196ab6bfe3SJack F Vogel continue; 2206ab6bfe3SJack F Vogel } 2216ab6bfe3SJack F Vogel phy_id |= (u32)(phy_reg & PHY_REVISION_MASK); 2226ab6bfe3SJack F Vogel break; 2236ab6bfe3SJack F Vogel } 2246ab6bfe3SJack F Vogel 2256ab6bfe3SJack F Vogel if (hw->phy.id) { 2266ab6bfe3SJack F Vogel if (hw->phy.id == phy_id) 2277609433eSJack F Vogel goto out; 2286ab6bfe3SJack F Vogel } else if (phy_id) { 2296ab6bfe3SJack F Vogel hw->phy.id = phy_id; 2306ab6bfe3SJack F Vogel hw->phy.revision = (u32)(phy_reg & ~PHY_REVISION_MASK); 2317609433eSJack F Vogel goto out; 2326ab6bfe3SJack F Vogel } 2336ab6bfe3SJack F Vogel 2346ab6bfe3SJack F Vogel /* In case the PHY needs to be in mdio slow mode, 2356ab6bfe3SJack F Vogel * set slow mode and try to get the PHY id again. 2366ab6bfe3SJack F Vogel */ 2377609433eSJack F Vogel if (hw->mac.type < e1000_pch_lpt) { 2386ab6bfe3SJack F Vogel hw->phy.ops.release(hw); 2396ab6bfe3SJack F Vogel ret_val = e1000_set_mdio_slow_mode_hv(hw); 2406ab6bfe3SJack F Vogel if (!ret_val) 2416ab6bfe3SJack F Vogel ret_val = e1000_get_phy_id(hw); 2426ab6bfe3SJack F Vogel hw->phy.ops.acquire(hw); 2437609433eSJack F Vogel } 2446ab6bfe3SJack F Vogel 2457609433eSJack F Vogel if (ret_val) 2467609433eSJack F Vogel return FALSE; 2477609433eSJack F Vogel out: 248295df609SEric Joyner if (hw->mac.type >= e1000_pch_lpt) { 249c80429ceSEric Joyner /* Only unforce SMBus if ME is not active */ 250c80429ceSEric Joyner if (!(E1000_READ_REG(hw, E1000_FWSM) & 251c80429ceSEric Joyner E1000_ICH_FWSM_FW_VALID)) { 2527609433eSJack F Vogel /* Unforce SMBus mode in PHY */ 2537609433eSJack F Vogel hw->phy.ops.read_reg_locked(hw, CV_SMB_CTRL, &phy_reg); 2547609433eSJack F Vogel phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS; 2557609433eSJack F Vogel hw->phy.ops.write_reg_locked(hw, CV_SMB_CTRL, phy_reg); 2567609433eSJack F Vogel 2577609433eSJack F Vogel /* Unforce SMBus mode in MAC */ 2587609433eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT); 2597609433eSJack F Vogel mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS; 2607609433eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg); 2617609433eSJack F Vogel } 262c80429ceSEric Joyner } 2637609433eSJack F Vogel 2647609433eSJack F Vogel return TRUE; 2657609433eSJack F Vogel } 2667609433eSJack F Vogel 2677609433eSJack F Vogel /** 2687609433eSJack F Vogel * e1000_toggle_lanphypc_pch_lpt - toggle the LANPHYPC pin value 2697609433eSJack F Vogel * @hw: pointer to the HW structure 2707609433eSJack F Vogel * 2717609433eSJack F Vogel * Toggling the LANPHYPC pin value fully power-cycles the PHY and is 2727609433eSJack F Vogel * used to reset the PHY to a quiescent state when necessary. 2737609433eSJack F Vogel **/ 2748cc64f1eSJack F Vogel static void e1000_toggle_lanphypc_pch_lpt(struct e1000_hw *hw) 2757609433eSJack F Vogel { 2767609433eSJack F Vogel u32 mac_reg; 2777609433eSJack F Vogel 2787609433eSJack F Vogel DEBUGFUNC("e1000_toggle_lanphypc_pch_lpt"); 2797609433eSJack F Vogel 2807609433eSJack F Vogel /* Set Phy Config Counter to 50msec */ 2817609433eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM3); 2827609433eSJack F Vogel mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK; 2837609433eSJack F Vogel mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC; 2847609433eSJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM3, mac_reg); 2857609433eSJack F Vogel 2867609433eSJack F Vogel /* Toggle LANPHYPC Value bit */ 2877609433eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_CTRL); 2887609433eSJack F Vogel mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE; 2897609433eSJack F Vogel mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE; 2907609433eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, mac_reg); 2917609433eSJack F Vogel E1000_WRITE_FLUSH(hw); 292e760e292SSean Bruno msec_delay(1); 2937609433eSJack F Vogel mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE; 2947609433eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, mac_reg); 2957609433eSJack F Vogel E1000_WRITE_FLUSH(hw); 2967609433eSJack F Vogel 2977609433eSJack F Vogel if (hw->mac.type < e1000_pch_lpt) { 2987609433eSJack F Vogel msec_delay(50); 2997609433eSJack F Vogel } else { 3007609433eSJack F Vogel u16 count = 20; 3017609433eSJack F Vogel 3027609433eSJack F Vogel do { 3037609433eSJack F Vogel msec_delay(5); 3047609433eSJack F Vogel } while (!(E1000_READ_REG(hw, E1000_CTRL_EXT) & 3057609433eSJack F Vogel E1000_CTRL_EXT_LPCD) && count--); 3067609433eSJack F Vogel 3077609433eSJack F Vogel msec_delay(30); 3087609433eSJack F Vogel } 3096ab6bfe3SJack F Vogel } 3106ab6bfe3SJack F Vogel 3116ab6bfe3SJack F Vogel /** 3126ab6bfe3SJack F Vogel * e1000_init_phy_workarounds_pchlan - PHY initialization workarounds 3136ab6bfe3SJack F Vogel * @hw: pointer to the HW structure 3146ab6bfe3SJack F Vogel * 3156ab6bfe3SJack F Vogel * Workarounds/flow necessary for PHY initialization during driver load 3166ab6bfe3SJack F Vogel * and resume paths. 3176ab6bfe3SJack F Vogel **/ 3186ab6bfe3SJack F Vogel static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) 3196ab6bfe3SJack F Vogel { 3206ab6bfe3SJack F Vogel u32 mac_reg, fwsm = E1000_READ_REG(hw, E1000_FWSM); 3216ab6bfe3SJack F Vogel s32 ret_val; 3226ab6bfe3SJack F Vogel 3236ab6bfe3SJack F Vogel DEBUGFUNC("e1000_init_phy_workarounds_pchlan"); 3246ab6bfe3SJack F Vogel 3256ab6bfe3SJack F Vogel /* Gate automatic PHY configuration by hardware on managed and 3266ab6bfe3SJack F Vogel * non-managed 82579 and newer adapters. 3276ab6bfe3SJack F Vogel */ 3286ab6bfe3SJack F Vogel e1000_gate_hw_phy_config_ich8lan(hw, TRUE); 3296ab6bfe3SJack F Vogel 3308cc64f1eSJack F Vogel /* It is not possible to be certain of the current state of ULP 3318cc64f1eSJack F Vogel * so forcibly disable it. 3328cc64f1eSJack F Vogel */ 3338cc64f1eSJack F Vogel hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_unknown; 3348cc64f1eSJack F Vogel e1000_disable_ulp_lpt_lp(hw, TRUE); 3358cc64f1eSJack F Vogel 3366ab6bfe3SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 3376ab6bfe3SJack F Vogel if (ret_val) { 3386ab6bfe3SJack F Vogel DEBUGOUT("Failed to initialize PHY flow\n"); 3396ab6bfe3SJack F Vogel goto out; 3406ab6bfe3SJack F Vogel } 3416ab6bfe3SJack F Vogel 3426ab6bfe3SJack F Vogel /* The MAC-PHY interconnect may be in SMBus mode. If the PHY is 3436ab6bfe3SJack F Vogel * inaccessible and resetting the PHY is not blocked, toggle the 3446ab6bfe3SJack F Vogel * LANPHYPC Value bit to force the interconnect to PCIe mode. 3456ab6bfe3SJack F Vogel */ 3466ab6bfe3SJack F Vogel switch (hw->mac.type) { 3476ab6bfe3SJack F Vogel case e1000_pch_lpt: 348c80429ceSEric Joyner case e1000_pch_spt: 3496fe4c0a0SSean Bruno case e1000_pch_cnp: 35059690eabSKevin Bowling case e1000_pch_tgp: 35159690eabSKevin Bowling case e1000_pch_adp: 35259690eabSKevin Bowling case e1000_pch_mtp: 3536ab6bfe3SJack F Vogel if (e1000_phy_is_accessible_pchlan(hw)) 3546ab6bfe3SJack F Vogel break; 3556ab6bfe3SJack F Vogel 3566ab6bfe3SJack F Vogel /* Before toggling LANPHYPC, see if PHY is accessible by 3576ab6bfe3SJack F Vogel * forcing MAC to SMBus mode first. 3586ab6bfe3SJack F Vogel */ 3596ab6bfe3SJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT); 3606ab6bfe3SJack F Vogel mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS; 3616ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg); 3626ab6bfe3SJack F Vogel 3637609433eSJack F Vogel /* Wait 50 milliseconds for MAC to finish any retries 3647609433eSJack F Vogel * that it might be trying to perform from previous 3657609433eSJack F Vogel * attempts to acknowledge any phy read requests. 3667609433eSJack F Vogel */ 3677609433eSJack F Vogel msec_delay(50); 3687609433eSJack F Vogel 3696ab6bfe3SJack F Vogel /* fall-through */ 3706ab6bfe3SJack F Vogel case e1000_pch2lan: 3717609433eSJack F Vogel if (e1000_phy_is_accessible_pchlan(hw)) 3726ab6bfe3SJack F Vogel break; 3736ab6bfe3SJack F Vogel 3746ab6bfe3SJack F Vogel /* fall-through */ 3756ab6bfe3SJack F Vogel case e1000_pchlan: 3766ab6bfe3SJack F Vogel if ((hw->mac.type == e1000_pchlan) && 3776ab6bfe3SJack F Vogel (fwsm & E1000_ICH_FWSM_FW_VALID)) 3786ab6bfe3SJack F Vogel break; 3796ab6bfe3SJack F Vogel 3806ab6bfe3SJack F Vogel if (hw->phy.ops.check_reset_block(hw)) { 3816ab6bfe3SJack F Vogel DEBUGOUT("Required LANPHYPC toggle blocked by ME\n"); 3827609433eSJack F Vogel ret_val = -E1000_ERR_PHY; 3836ab6bfe3SJack F Vogel break; 3846ab6bfe3SJack F Vogel } 3856ab6bfe3SJack F Vogel 3867609433eSJack F Vogel /* Toggle LANPHYPC Value bit */ 3877609433eSJack F Vogel e1000_toggle_lanphypc_pch_lpt(hw); 3887609433eSJack F Vogel if (hw->mac.type >= e1000_pch_lpt) { 3897609433eSJack F Vogel if (e1000_phy_is_accessible_pchlan(hw)) 3907609433eSJack F Vogel break; 3916ab6bfe3SJack F Vogel 3926ab6bfe3SJack F Vogel /* Toggling LANPHYPC brings the PHY out of SMBus mode 3937609433eSJack F Vogel * so ensure that the MAC is also out of SMBus mode 3946ab6bfe3SJack F Vogel */ 3956ab6bfe3SJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT); 3966ab6bfe3SJack F Vogel mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS; 3976ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg); 3986ab6bfe3SJack F Vogel 3997609433eSJack F Vogel if (e1000_phy_is_accessible_pchlan(hw)) 4007609433eSJack F Vogel break; 4017609433eSJack F Vogel 4027609433eSJack F Vogel ret_val = -E1000_ERR_PHY; 4036ab6bfe3SJack F Vogel } 4046ab6bfe3SJack F Vogel break; 4056ab6bfe3SJack F Vogel default: 4066ab6bfe3SJack F Vogel break; 4076ab6bfe3SJack F Vogel } 4086ab6bfe3SJack F Vogel 4096ab6bfe3SJack F Vogel hw->phy.ops.release(hw); 4107609433eSJack F Vogel if (!ret_val) { 4117609433eSJack F Vogel 4127609433eSJack F Vogel /* Check to see if able to reset PHY. Print error if not */ 4137609433eSJack F Vogel if (hw->phy.ops.check_reset_block(hw)) { 4147609433eSJack F Vogel ERROR_REPORT("Reset blocked by ME\n"); 4157609433eSJack F Vogel goto out; 4167609433eSJack F Vogel } 4176ab6bfe3SJack F Vogel 4186ab6bfe3SJack F Vogel /* Reset the PHY before any access to it. Doing so, ensures 4196ab6bfe3SJack F Vogel * that the PHY is in a known good state before we read/write 4206ab6bfe3SJack F Vogel * PHY registers. The generic reset is sufficient here, 4216ab6bfe3SJack F Vogel * because we haven't determined the PHY type yet. 4226ab6bfe3SJack F Vogel */ 4236ab6bfe3SJack F Vogel ret_val = e1000_phy_hw_reset_generic(hw); 4247609433eSJack F Vogel if (ret_val) 4257609433eSJack F Vogel goto out; 4267609433eSJack F Vogel 4277609433eSJack F Vogel /* On a successful reset, possibly need to wait for the PHY 4287609433eSJack F Vogel * to quiesce to an accessible state before returning control 4297609433eSJack F Vogel * to the calling function. If the PHY does not quiesce, then 4307609433eSJack F Vogel * return E1000E_BLK_PHY_RESET, as this is the condition that 4317609433eSJack F Vogel * the PHY is in. 4327609433eSJack F Vogel */ 4337609433eSJack F Vogel ret_val = hw->phy.ops.check_reset_block(hw); 4347609433eSJack F Vogel if (ret_val) 4357609433eSJack F Vogel ERROR_REPORT("ME blocked access to PHY after reset\n"); 4367609433eSJack F Vogel } 4376ab6bfe3SJack F Vogel 4386ab6bfe3SJack F Vogel out: 4396ab6bfe3SJack F Vogel /* Ungate automatic PHY configuration on non-managed 82579 */ 4406ab6bfe3SJack F Vogel if ((hw->mac.type == e1000_pch2lan) && 4416ab6bfe3SJack F Vogel !(fwsm & E1000_ICH_FWSM_FW_VALID)) { 4426ab6bfe3SJack F Vogel msec_delay(10); 4436ab6bfe3SJack F Vogel e1000_gate_hw_phy_config_ich8lan(hw, FALSE); 4446ab6bfe3SJack F Vogel } 4456ab6bfe3SJack F Vogel 4466ab6bfe3SJack F Vogel return ret_val; 4474dab5c37SJack F Vogel } 4484dab5c37SJack F Vogel 4498cfa0ad2SJack F Vogel /** 4509d81738fSJack F Vogel * e1000_init_phy_params_pchlan - Initialize PHY function pointers 4519d81738fSJack F Vogel * @hw: pointer to the HW structure 4529d81738fSJack F Vogel * 4539d81738fSJack F Vogel * Initialize family-specific PHY parameters and function pointers. 4549d81738fSJack F Vogel **/ 4559d81738fSJack F Vogel static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) 4569d81738fSJack F Vogel { 4579d81738fSJack F Vogel struct e1000_phy_info *phy = &hw->phy; 4586ab6bfe3SJack F Vogel s32 ret_val; 4599d81738fSJack F Vogel 4609d81738fSJack F Vogel DEBUGFUNC("e1000_init_phy_params_pchlan"); 4619d81738fSJack F Vogel 4629d81738fSJack F Vogel phy->addr = 1; 4639d81738fSJack F Vogel phy->reset_delay_us = 100; 4649d81738fSJack F Vogel 4659d81738fSJack F Vogel phy->ops.acquire = e1000_acquire_swflag_ich8lan; 4669d81738fSJack F Vogel phy->ops.check_reset_block = e1000_check_reset_block_ich8lan; 4679d81738fSJack F Vogel phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan; 4684dab5c37SJack F Vogel phy->ops.set_page = e1000_set_page_igp; 4699d81738fSJack F Vogel phy->ops.read_reg = e1000_read_phy_reg_hv; 4704edd8523SJack F Vogel phy->ops.read_reg_locked = e1000_read_phy_reg_hv_locked; 4714dab5c37SJack F Vogel phy->ops.read_reg_page = e1000_read_phy_reg_page_hv; 4729d81738fSJack F Vogel phy->ops.release = e1000_release_swflag_ich8lan; 4739d81738fSJack F Vogel phy->ops.reset = e1000_phy_hw_reset_ich8lan; 4744edd8523SJack F Vogel phy->ops.set_d0_lplu_state = e1000_set_lplu_state_pchlan; 4754edd8523SJack F Vogel phy->ops.set_d3_lplu_state = e1000_set_lplu_state_pchlan; 4769d81738fSJack F Vogel phy->ops.write_reg = e1000_write_phy_reg_hv; 4774edd8523SJack F Vogel phy->ops.write_reg_locked = e1000_write_phy_reg_hv_locked; 4784dab5c37SJack F Vogel phy->ops.write_reg_page = e1000_write_phy_reg_page_hv; 4799d81738fSJack F Vogel phy->ops.power_up = e1000_power_up_phy_copper; 4809d81738fSJack F Vogel phy->ops.power_down = e1000_power_down_phy_copper_ich8lan; 4819d81738fSJack F Vogel phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; 4829d81738fSJack F Vogel 4839d81738fSJack F Vogel phy->id = e1000_phy_unknown; 4846ab6bfe3SJack F Vogel 4856ab6bfe3SJack F Vogel ret_val = e1000_init_phy_workarounds_pchlan(hw); 4866ab6bfe3SJack F Vogel if (ret_val) 4876ab6bfe3SJack F Vogel return ret_val; 4886ab6bfe3SJack F Vogel 4896ab6bfe3SJack F Vogel if (phy->id == e1000_phy_unknown) 4907d9119bdSJack F Vogel switch (hw->mac.type) { 4917d9119bdSJack F Vogel default: 492a69ed8dfSJack F Vogel ret_val = e1000_get_phy_id(hw); 493a69ed8dfSJack F Vogel if (ret_val) 4946ab6bfe3SJack F Vogel return ret_val; 4957d9119bdSJack F Vogel if ((phy->id != 0) && (phy->id != PHY_REVISION_MASK)) 4967d9119bdSJack F Vogel break; 4977d9119bdSJack F Vogel /* fall-through */ 4987d9119bdSJack F Vogel case e1000_pch2lan: 4996ab6bfe3SJack F Vogel case e1000_pch_lpt: 500c80429ceSEric Joyner case e1000_pch_spt: 5016fe4c0a0SSean Bruno case e1000_pch_cnp: 50259690eabSKevin Bowling case e1000_pch_tgp: 50359690eabSKevin Bowling case e1000_pch_adp: 50459690eabSKevin Bowling case e1000_pch_mtp: 5056ab6bfe3SJack F Vogel /* In case the PHY needs to be in mdio slow mode, 506a69ed8dfSJack F Vogel * set slow mode and try to get the PHY id again. 507a69ed8dfSJack F Vogel */ 508a69ed8dfSJack F Vogel ret_val = e1000_set_mdio_slow_mode_hv(hw); 509a69ed8dfSJack F Vogel if (ret_val) 5106ab6bfe3SJack F Vogel return ret_val; 511a69ed8dfSJack F Vogel ret_val = e1000_get_phy_id(hw); 512a69ed8dfSJack F Vogel if (ret_val) 5136ab6bfe3SJack F Vogel return ret_val; 5147d9119bdSJack F Vogel break; 515a69ed8dfSJack F Vogel } 5169d81738fSJack F Vogel phy->type = e1000_get_phy_type_from_id(phy->id); 5179d81738fSJack F Vogel 5184edd8523SJack F Vogel switch (phy->type) { 5194edd8523SJack F Vogel case e1000_phy_82577: 5207d9119bdSJack F Vogel case e1000_phy_82579: 5216ab6bfe3SJack F Vogel case e1000_phy_i217: 5229d81738fSJack F Vogel phy->ops.check_polarity = e1000_check_polarity_82577; 5239d81738fSJack F Vogel phy->ops.force_speed_duplex = 5249d81738fSJack F Vogel e1000_phy_force_speed_duplex_82577; 5259d81738fSJack F Vogel phy->ops.get_cable_length = e1000_get_cable_length_82577; 5269d81738fSJack F Vogel phy->ops.get_info = e1000_get_phy_info_82577; 5279d81738fSJack F Vogel phy->ops.commit = e1000_phy_sw_reset_generic; 5288ec87fc5SJack F Vogel break; 5294edd8523SJack F Vogel case e1000_phy_82578: 5304edd8523SJack F Vogel phy->ops.check_polarity = e1000_check_polarity_m88; 5314edd8523SJack F Vogel phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88; 5324edd8523SJack F Vogel phy->ops.get_cable_length = e1000_get_cable_length_m88; 5334edd8523SJack F Vogel phy->ops.get_info = e1000_get_phy_info_m88; 5344edd8523SJack F Vogel break; 5354edd8523SJack F Vogel default: 5364edd8523SJack F Vogel ret_val = -E1000_ERR_PHY; 5374edd8523SJack F Vogel break; 5389d81738fSJack F Vogel } 5399d81738fSJack F Vogel 5409d81738fSJack F Vogel return ret_val; 5419d81738fSJack F Vogel } 5429d81738fSJack F Vogel 5439d81738fSJack F Vogel /** 5448cfa0ad2SJack F Vogel * e1000_init_phy_params_ich8lan - Initialize PHY function pointers 5458cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 5468cfa0ad2SJack F Vogel * 5478cfa0ad2SJack F Vogel * Initialize family-specific PHY parameters and function pointers. 5488cfa0ad2SJack F Vogel **/ 5498cfa0ad2SJack F Vogel static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) 5508cfa0ad2SJack F Vogel { 5518cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 5526ab6bfe3SJack F Vogel s32 ret_val; 5538cfa0ad2SJack F Vogel u16 i = 0; 5548cfa0ad2SJack F Vogel 5558cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_phy_params_ich8lan"); 5568cfa0ad2SJack F Vogel 5578cfa0ad2SJack F Vogel phy->addr = 1; 5588cfa0ad2SJack F Vogel phy->reset_delay_us = 100; 5598cfa0ad2SJack F Vogel 5608cfa0ad2SJack F Vogel phy->ops.acquire = e1000_acquire_swflag_ich8lan; 5618cfa0ad2SJack F Vogel phy->ops.check_reset_block = e1000_check_reset_block_ich8lan; 5628cfa0ad2SJack F Vogel phy->ops.get_cable_length = e1000_get_cable_length_igp_2; 5638cfa0ad2SJack F Vogel phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan; 5648cfa0ad2SJack F Vogel phy->ops.read_reg = e1000_read_phy_reg_igp; 5658cfa0ad2SJack F Vogel phy->ops.release = e1000_release_swflag_ich8lan; 5668cfa0ad2SJack F Vogel phy->ops.reset = e1000_phy_hw_reset_ich8lan; 5678cfa0ad2SJack F Vogel phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan; 5688cfa0ad2SJack F Vogel phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan; 5698cfa0ad2SJack F Vogel phy->ops.write_reg = e1000_write_phy_reg_igp; 5708cfa0ad2SJack F Vogel phy->ops.power_up = e1000_power_up_phy_copper; 5718cfa0ad2SJack F Vogel phy->ops.power_down = e1000_power_down_phy_copper_ich8lan; 5728cfa0ad2SJack F Vogel 5736ab6bfe3SJack F Vogel /* We may need to do this twice - once for IGP and if that fails, 5748cfa0ad2SJack F Vogel * we'll set BM func pointers and try again 5758cfa0ad2SJack F Vogel */ 5768cfa0ad2SJack F Vogel ret_val = e1000_determine_phy_address(hw); 5778cfa0ad2SJack F Vogel if (ret_val) { 5788cfa0ad2SJack F Vogel phy->ops.write_reg = e1000_write_phy_reg_bm; 5798cfa0ad2SJack F Vogel phy->ops.read_reg = e1000_read_phy_reg_bm; 5808cfa0ad2SJack F Vogel ret_val = e1000_determine_phy_address(hw); 5818cfa0ad2SJack F Vogel if (ret_val) { 582d035aa2dSJack F Vogel DEBUGOUT("Cannot determine PHY addr. Erroring out\n"); 5836ab6bfe3SJack F Vogel return ret_val; 5848cfa0ad2SJack F Vogel } 5858cfa0ad2SJack F Vogel } 5868cfa0ad2SJack F Vogel 5878cfa0ad2SJack F Vogel phy->id = 0; 5888cfa0ad2SJack F Vogel while ((e1000_phy_unknown == e1000_get_phy_type_from_id(phy->id)) && 5898cfa0ad2SJack F Vogel (i++ < 100)) { 5908cfa0ad2SJack F Vogel msec_delay(1); 5918cfa0ad2SJack F Vogel ret_val = e1000_get_phy_id(hw); 5928cfa0ad2SJack F Vogel if (ret_val) 5936ab6bfe3SJack F Vogel return ret_val; 5948cfa0ad2SJack F Vogel } 5958cfa0ad2SJack F Vogel 5968cfa0ad2SJack F Vogel /* Verify phy id */ 5978cfa0ad2SJack F Vogel switch (phy->id) { 5988cfa0ad2SJack F Vogel case IGP03E1000_E_PHY_ID: 5998cfa0ad2SJack F Vogel phy->type = e1000_phy_igp_3; 6008cfa0ad2SJack F Vogel phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; 6014edd8523SJack F Vogel phy->ops.read_reg_locked = e1000_read_phy_reg_igp_locked; 6024edd8523SJack F Vogel phy->ops.write_reg_locked = e1000_write_phy_reg_igp_locked; 6034edd8523SJack F Vogel phy->ops.get_info = e1000_get_phy_info_igp; 6044edd8523SJack F Vogel phy->ops.check_polarity = e1000_check_polarity_igp; 6054edd8523SJack F Vogel phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp; 6068cfa0ad2SJack F Vogel break; 6078cfa0ad2SJack F Vogel case IFE_E_PHY_ID: 6088cfa0ad2SJack F Vogel case IFE_PLUS_E_PHY_ID: 6098cfa0ad2SJack F Vogel case IFE_C_E_PHY_ID: 6108cfa0ad2SJack F Vogel phy->type = e1000_phy_ife; 6118cfa0ad2SJack F Vogel phy->autoneg_mask = E1000_ALL_NOT_GIG; 6124edd8523SJack F Vogel phy->ops.get_info = e1000_get_phy_info_ife; 6134edd8523SJack F Vogel phy->ops.check_polarity = e1000_check_polarity_ife; 6144edd8523SJack F Vogel phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife; 6158cfa0ad2SJack F Vogel break; 6168cfa0ad2SJack F Vogel case BME1000_E_PHY_ID: 6178cfa0ad2SJack F Vogel phy->type = e1000_phy_bm; 6188cfa0ad2SJack F Vogel phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; 6198cfa0ad2SJack F Vogel phy->ops.read_reg = e1000_read_phy_reg_bm; 6208cfa0ad2SJack F Vogel phy->ops.write_reg = e1000_write_phy_reg_bm; 6218cfa0ad2SJack F Vogel phy->ops.commit = e1000_phy_sw_reset_generic; 6224edd8523SJack F Vogel phy->ops.get_info = e1000_get_phy_info_m88; 6234edd8523SJack F Vogel phy->ops.check_polarity = e1000_check_polarity_m88; 6244edd8523SJack F Vogel phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88; 6258cfa0ad2SJack F Vogel break; 6268cfa0ad2SJack F Vogel default: 6276ab6bfe3SJack F Vogel return -E1000_ERR_PHY; 6286ab6bfe3SJack F Vogel break; 6298cfa0ad2SJack F Vogel } 6308cfa0ad2SJack F Vogel 6316ab6bfe3SJack F Vogel return E1000_SUCCESS; 6328cfa0ad2SJack F Vogel } 6338cfa0ad2SJack F Vogel 6348cfa0ad2SJack F Vogel /** 6358cfa0ad2SJack F Vogel * e1000_init_nvm_params_ich8lan - Initialize NVM function pointers 6368cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 6378cfa0ad2SJack F Vogel * 6388cfa0ad2SJack F Vogel * Initialize family-specific NVM parameters and function 6398cfa0ad2SJack F Vogel * pointers. 6408cfa0ad2SJack F Vogel **/ 6418cfa0ad2SJack F Vogel static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw) 6428cfa0ad2SJack F Vogel { 6438cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 644daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 6458cfa0ad2SJack F Vogel u32 gfpreg, sector_base_addr, sector_end_addr; 6468cfa0ad2SJack F Vogel u16 i; 647c80429ceSEric Joyner u32 nvm_size; 6488cfa0ad2SJack F Vogel 6498cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_nvm_params_ich8lan"); 6508cfa0ad2SJack F Vogel 6518cc64f1eSJack F Vogel nvm->type = e1000_nvm_flash_sw; 652c80429ceSEric Joyner 653295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt) { 654c80429ceSEric Joyner /* in SPT, gfpreg doesn't exist. NVM size is taken from the 655c80429ceSEric Joyner * STRAP register. This is because in SPT the GbE Flash region 656c80429ceSEric Joyner * is no longer accessed through the flash registers. Instead, 657c80429ceSEric Joyner * the mechanism has changed, and the Flash region access 658c80429ceSEric Joyner * registers are now implemented in GbE memory space. 659c80429ceSEric Joyner */ 660c80429ceSEric Joyner nvm->flash_base_addr = 0; 661c80429ceSEric Joyner nvm_size = 662c80429ceSEric Joyner (((E1000_READ_REG(hw, E1000_STRAP) >> 1) & 0x1F) + 1) 663c80429ceSEric Joyner * NVM_SIZE_MULTIPLIER; 664c80429ceSEric Joyner nvm->flash_bank_size = nvm_size / 2; 665c80429ceSEric Joyner /* Adjust to word count */ 666c80429ceSEric Joyner nvm->flash_bank_size /= sizeof(u16); 667c80429ceSEric Joyner /* Set the base address for flash register access */ 668c80429ceSEric Joyner hw->flash_address = hw->hw_addr + E1000_FLASH_BASE_ADDR; 669c80429ceSEric Joyner } else { 670c80429ceSEric Joyner /* Can't read flash registers if register set isn't mapped. */ 6718cfa0ad2SJack F Vogel if (!hw->flash_address) { 6728cfa0ad2SJack F Vogel DEBUGOUT("ERROR: Flash registers not mapped\n"); 6736ab6bfe3SJack F Vogel return -E1000_ERR_CONFIG; 6748cfa0ad2SJack F Vogel } 6758cfa0ad2SJack F Vogel 6768cfa0ad2SJack F Vogel gfpreg = E1000_READ_FLASH_REG(hw, ICH_FLASH_GFPREG); 6778cfa0ad2SJack F Vogel 6786ab6bfe3SJack F Vogel /* sector_X_addr is a "sector"-aligned address (4096 bytes) 6798cfa0ad2SJack F Vogel * Add 1 to sector_end_addr since this sector is included in 6808cfa0ad2SJack F Vogel * the overall size. 6818cfa0ad2SJack F Vogel */ 6828cfa0ad2SJack F Vogel sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK; 6838cfa0ad2SJack F Vogel sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1; 6848cfa0ad2SJack F Vogel 6858cfa0ad2SJack F Vogel /* flash_base_addr is byte-aligned */ 686c80429ceSEric Joyner nvm->flash_base_addr = sector_base_addr 687c80429ceSEric Joyner << FLASH_SECTOR_ADDR_SHIFT; 6888cfa0ad2SJack F Vogel 6896ab6bfe3SJack F Vogel /* find total size of the NVM, then cut in half since the total 6908cfa0ad2SJack F Vogel * size represents two separate NVM banks. 6918cfa0ad2SJack F Vogel */ 6927609433eSJack F Vogel nvm->flash_bank_size = ((sector_end_addr - sector_base_addr) 6937609433eSJack F Vogel << FLASH_SECTOR_ADDR_SHIFT); 6948cfa0ad2SJack F Vogel nvm->flash_bank_size /= 2; 6958cfa0ad2SJack F Vogel /* Adjust to word count */ 6968cfa0ad2SJack F Vogel nvm->flash_bank_size /= sizeof(u16); 697c80429ceSEric Joyner } 6988cfa0ad2SJack F Vogel 6998cfa0ad2SJack F Vogel nvm->word_size = E1000_SHADOW_RAM_WORDS; 7008cfa0ad2SJack F Vogel 7018cfa0ad2SJack F Vogel /* Clear shadow ram */ 7028cfa0ad2SJack F Vogel for (i = 0; i < nvm->word_size; i++) { 7038cfa0ad2SJack F Vogel dev_spec->shadow_ram[i].modified = FALSE; 7048cfa0ad2SJack F Vogel dev_spec->shadow_ram[i].value = 0xFFFF; 7058cfa0ad2SJack F Vogel } 7068cfa0ad2SJack F Vogel 7078cfa0ad2SJack F Vogel /* Function Pointers */ 7084edd8523SJack F Vogel nvm->ops.acquire = e1000_acquire_nvm_ich8lan; 7094edd8523SJack F Vogel nvm->ops.release = e1000_release_nvm_ich8lan; 710295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt) { 711c80429ceSEric Joyner nvm->ops.read = e1000_read_nvm_spt; 712c80429ceSEric Joyner nvm->ops.update = e1000_update_nvm_checksum_spt; 713c80429ceSEric Joyner } else { 7148cfa0ad2SJack F Vogel nvm->ops.read = e1000_read_nvm_ich8lan; 7158cfa0ad2SJack F Vogel nvm->ops.update = e1000_update_nvm_checksum_ich8lan; 716c80429ceSEric Joyner } 7178cfa0ad2SJack F Vogel nvm->ops.valid_led_default = e1000_valid_led_default_ich8lan; 7188cfa0ad2SJack F Vogel nvm->ops.validate = e1000_validate_nvm_checksum_ich8lan; 7198cfa0ad2SJack F Vogel nvm->ops.write = e1000_write_nvm_ich8lan; 7208cfa0ad2SJack F Vogel 7216ab6bfe3SJack F Vogel return E1000_SUCCESS; 7228cfa0ad2SJack F Vogel } 7238cfa0ad2SJack F Vogel 7248cfa0ad2SJack F Vogel /** 7258cfa0ad2SJack F Vogel * e1000_init_mac_params_ich8lan - Initialize MAC function pointers 7268cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 7278cfa0ad2SJack F Vogel * 7288cfa0ad2SJack F Vogel * Initialize family-specific MAC parameters and function 7298cfa0ad2SJack F Vogel * pointers. 7308cfa0ad2SJack F Vogel **/ 7318cfa0ad2SJack F Vogel static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) 7328cfa0ad2SJack F Vogel { 7338cfa0ad2SJack F Vogel struct e1000_mac_info *mac = &hw->mac; 734*fc7682b1SKevin Bowling u16 pci_cfg; 7358cfa0ad2SJack F Vogel 7368cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_mac_params_ich8lan"); 7378cfa0ad2SJack F Vogel 7388cfa0ad2SJack F Vogel /* Set media type function pointer */ 7398cfa0ad2SJack F Vogel hw->phy.media_type = e1000_media_type_copper; 7408cfa0ad2SJack F Vogel 7418cfa0ad2SJack F Vogel /* Set mta register count */ 7428cfa0ad2SJack F Vogel mac->mta_reg_count = 32; 7438cfa0ad2SJack F Vogel /* Set rar entry count */ 7448cfa0ad2SJack F Vogel mac->rar_entry_count = E1000_ICH_RAR_ENTRIES; 7458cfa0ad2SJack F Vogel if (mac->type == e1000_ich8lan) 7468cfa0ad2SJack F Vogel mac->rar_entry_count--; 7478cfa0ad2SJack F Vogel /* Set if part includes ASF firmware */ 7488cfa0ad2SJack F Vogel mac->asf_firmware_present = TRUE; 7498ec87fc5SJack F Vogel /* FWSM register */ 7508ec87fc5SJack F Vogel mac->has_fwsm = TRUE; 7518ec87fc5SJack F Vogel /* ARC subsystem not supported */ 7528ec87fc5SJack F Vogel mac->arc_subsystem_valid = FALSE; 7534edd8523SJack F Vogel /* Adaptive IFS supported */ 7544edd8523SJack F Vogel mac->adaptive_ifs = TRUE; 7558cfa0ad2SJack F Vogel 7568cfa0ad2SJack F Vogel /* Function pointers */ 7578cfa0ad2SJack F Vogel 7588cfa0ad2SJack F Vogel /* bus type/speed/width */ 7598cfa0ad2SJack F Vogel mac->ops.get_bus_info = e1000_get_bus_info_ich8lan; 760daf9197cSJack F Vogel /* function id */ 761daf9197cSJack F Vogel mac->ops.set_lan_id = e1000_set_lan_id_single_port; 7628cfa0ad2SJack F Vogel /* reset */ 7638cfa0ad2SJack F Vogel mac->ops.reset_hw = e1000_reset_hw_ich8lan; 7648cfa0ad2SJack F Vogel /* hw initialization */ 7658cfa0ad2SJack F Vogel mac->ops.init_hw = e1000_init_hw_ich8lan; 7668cfa0ad2SJack F Vogel /* link setup */ 7678cfa0ad2SJack F Vogel mac->ops.setup_link = e1000_setup_link_ich8lan; 7688cfa0ad2SJack F Vogel /* physical interface setup */ 7698cfa0ad2SJack F Vogel mac->ops.setup_physical_interface = e1000_setup_copper_link_ich8lan; 7708cfa0ad2SJack F Vogel /* check for link */ 7714edd8523SJack F Vogel mac->ops.check_for_link = e1000_check_for_copper_link_ich8lan; 7728cfa0ad2SJack F Vogel /* link info */ 7738cfa0ad2SJack F Vogel mac->ops.get_link_up_info = e1000_get_link_up_info_ich8lan; 7748cfa0ad2SJack F Vogel /* multicast address update */ 7758cfa0ad2SJack F Vogel mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic; 776d035aa2dSJack F Vogel /* clear hardware counters */ 777d035aa2dSJack F Vogel mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan; 778d035aa2dSJack F Vogel 7796ab6bfe3SJack F Vogel /* LED and other operations */ 780d035aa2dSJack F Vogel switch (mac->type) { 781d035aa2dSJack F Vogel case e1000_ich8lan: 782d035aa2dSJack F Vogel case e1000_ich9lan: 783d035aa2dSJack F Vogel case e1000_ich10lan: 7847d9119bdSJack F Vogel /* check management mode */ 7857d9119bdSJack F Vogel mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan; 786d035aa2dSJack F Vogel /* ID LED init */ 787d035aa2dSJack F Vogel mac->ops.id_led_init = e1000_id_led_init_generic; 7888cfa0ad2SJack F Vogel /* blink LED */ 7898cfa0ad2SJack F Vogel mac->ops.blink_led = e1000_blink_led_generic; 7908cfa0ad2SJack F Vogel /* setup LED */ 7918cfa0ad2SJack F Vogel mac->ops.setup_led = e1000_setup_led_generic; 7928cfa0ad2SJack F Vogel /* cleanup LED */ 7938cfa0ad2SJack F Vogel mac->ops.cleanup_led = e1000_cleanup_led_ich8lan; 7948cfa0ad2SJack F Vogel /* turn on/off LED */ 7958cfa0ad2SJack F Vogel mac->ops.led_on = e1000_led_on_ich8lan; 7968cfa0ad2SJack F Vogel mac->ops.led_off = e1000_led_off_ich8lan; 797d035aa2dSJack F Vogel break; 7987d9119bdSJack F Vogel case e1000_pch2lan: 7997d9119bdSJack F Vogel mac->rar_entry_count = E1000_PCH2_RAR_ENTRIES; 8007d9119bdSJack F Vogel mac->ops.rar_set = e1000_rar_set_pch2lan; 8016ab6bfe3SJack F Vogel /* fall-through */ 8026ab6bfe3SJack F Vogel case e1000_pch_lpt: 803c80429ceSEric Joyner case e1000_pch_spt: 8046fe4c0a0SSean Bruno case e1000_pch_cnp: 80559690eabSKevin Bowling case e1000_pch_tgp: 80659690eabSKevin Bowling case e1000_pch_adp: 80759690eabSKevin Bowling case e1000_pch_mtp: 808730d3130SJack F Vogel /* multicast address update for pch2 */ 809730d3130SJack F Vogel mac->ops.update_mc_addr_list = 810730d3130SJack F Vogel e1000_update_mc_addr_list_pch2lan; 811c80429ceSEric Joyner /* fall-through */ 8129d81738fSJack F Vogel case e1000_pchlan: 813*fc7682b1SKevin Bowling /* save PCH revision_id */ 814*fc7682b1SKevin Bowling e1000_read_pci_cfg(hw, E1000_PCI_REVISION_ID_REG, &pci_cfg); 815*fc7682b1SKevin Bowling /* SPT uses full byte for revision ID, 816*fc7682b1SKevin Bowling * as opposed to previous generations 817*fc7682b1SKevin Bowling */ 818*fc7682b1SKevin Bowling if (hw->mac.type >= e1000_pch_spt) 819*fc7682b1SKevin Bowling hw->revision_id = (u8)(pci_cfg &= 0x00FF); 820*fc7682b1SKevin Bowling else 821*fc7682b1SKevin Bowling hw->revision_id = (u8)(pci_cfg &= 0x000F); 8227d9119bdSJack F Vogel /* check management mode */ 8237d9119bdSJack F Vogel mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan; 8249d81738fSJack F Vogel /* ID LED init */ 8259d81738fSJack F Vogel mac->ops.id_led_init = e1000_id_led_init_pchlan; 8269d81738fSJack F Vogel /* setup LED */ 8279d81738fSJack F Vogel mac->ops.setup_led = e1000_setup_led_pchlan; 8289d81738fSJack F Vogel /* cleanup LED */ 8299d81738fSJack F Vogel mac->ops.cleanup_led = e1000_cleanup_led_pchlan; 8309d81738fSJack F Vogel /* turn on/off LED */ 8319d81738fSJack F Vogel mac->ops.led_on = e1000_led_on_pchlan; 8329d81738fSJack F Vogel mac->ops.led_off = e1000_led_off_pchlan; 8339d81738fSJack F Vogel break; 834d035aa2dSJack F Vogel default: 835d035aa2dSJack F Vogel break; 836d035aa2dSJack F Vogel } 8378cfa0ad2SJack F Vogel 838295df609SEric Joyner if (mac->type >= e1000_pch_lpt) { 8396ab6bfe3SJack F Vogel mac->rar_entry_count = E1000_PCH_LPT_RAR_ENTRIES; 8406ab6bfe3SJack F Vogel mac->ops.rar_set = e1000_rar_set_pch_lpt; 8416ab6bfe3SJack F Vogel mac->ops.setup_physical_interface = e1000_setup_copper_link_pch_lpt; 842e373323fSSean Bruno mac->ops.set_obff_timer = e1000_set_obff_timer_pch_lpt; 8434dab5c37SJack F Vogel } 8444dab5c37SJack F Vogel 8458cfa0ad2SJack F Vogel /* Enable PCS Lock-loss workaround for ICH8 */ 8468cfa0ad2SJack F Vogel if (mac->type == e1000_ich8lan) 8478cfa0ad2SJack F Vogel e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, TRUE); 8488cfa0ad2SJack F Vogel 849daf9197cSJack F Vogel return E1000_SUCCESS; 8508cfa0ad2SJack F Vogel } 8518cfa0ad2SJack F Vogel 8528cfa0ad2SJack F Vogel /** 8536ab6bfe3SJack F Vogel * __e1000_access_emi_reg_locked - Read/write EMI register 8546ab6bfe3SJack F Vogel * @hw: pointer to the HW structure 855*fc7682b1SKevin Bowling * @address: EMI address to program 8566ab6bfe3SJack F Vogel * @data: pointer to value to read/write from/to the EMI address 8576ab6bfe3SJack F Vogel * @read: boolean flag to indicate read or write 8586ab6bfe3SJack F Vogel * 8596ab6bfe3SJack F Vogel * This helper function assumes the SW/FW/HW Semaphore is already acquired. 8606ab6bfe3SJack F Vogel **/ 8616ab6bfe3SJack F Vogel static s32 __e1000_access_emi_reg_locked(struct e1000_hw *hw, u16 address, 8626ab6bfe3SJack F Vogel u16 *data, bool read) 8636ab6bfe3SJack F Vogel { 8646ab6bfe3SJack F Vogel s32 ret_val; 8656ab6bfe3SJack F Vogel 8666ab6bfe3SJack F Vogel DEBUGFUNC("__e1000_access_emi_reg_locked"); 8676ab6bfe3SJack F Vogel 8686ab6bfe3SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_ADDR, address); 8696ab6bfe3SJack F Vogel if (ret_val) 8706ab6bfe3SJack F Vogel return ret_val; 8716ab6bfe3SJack F Vogel 8726ab6bfe3SJack F Vogel if (read) 8736ab6bfe3SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, I82579_EMI_DATA, 8746ab6bfe3SJack F Vogel data); 8756ab6bfe3SJack F Vogel else 8766ab6bfe3SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, I82579_EMI_DATA, 8776ab6bfe3SJack F Vogel *data); 8786ab6bfe3SJack F Vogel 8796ab6bfe3SJack F Vogel return ret_val; 8806ab6bfe3SJack F Vogel } 8816ab6bfe3SJack F Vogel 8826ab6bfe3SJack F Vogel /** 8836ab6bfe3SJack F Vogel * e1000_read_emi_reg_locked - Read Extended Management Interface register 8846ab6bfe3SJack F Vogel * @hw: pointer to the HW structure 8856ab6bfe3SJack F Vogel * @addr: EMI address to program 8866ab6bfe3SJack F Vogel * @data: value to be read from the EMI address 8876ab6bfe3SJack F Vogel * 8886ab6bfe3SJack F Vogel * Assumes the SW/FW/HW Semaphore is already acquired. 8896ab6bfe3SJack F Vogel **/ 8906ab6bfe3SJack F Vogel s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data) 8916ab6bfe3SJack F Vogel { 8926ab6bfe3SJack F Vogel DEBUGFUNC("e1000_read_emi_reg_locked"); 8936ab6bfe3SJack F Vogel 8946ab6bfe3SJack F Vogel return __e1000_access_emi_reg_locked(hw, addr, data, TRUE); 8956ab6bfe3SJack F Vogel } 8966ab6bfe3SJack F Vogel 8976ab6bfe3SJack F Vogel /** 8986ab6bfe3SJack F Vogel * e1000_write_emi_reg_locked - Write Extended Management Interface register 8996ab6bfe3SJack F Vogel * @hw: pointer to the HW structure 9006ab6bfe3SJack F Vogel * @addr: EMI address to program 9016ab6bfe3SJack F Vogel * @data: value to be written to the EMI address 9026ab6bfe3SJack F Vogel * 9036ab6bfe3SJack F Vogel * Assumes the SW/FW/HW Semaphore is already acquired. 9046ab6bfe3SJack F Vogel **/ 9057609433eSJack F Vogel s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data) 9066ab6bfe3SJack F Vogel { 9076ab6bfe3SJack F Vogel DEBUGFUNC("e1000_read_emi_reg_locked"); 9086ab6bfe3SJack F Vogel 9096ab6bfe3SJack F Vogel return __e1000_access_emi_reg_locked(hw, addr, &data, FALSE); 9106ab6bfe3SJack F Vogel } 9116ab6bfe3SJack F Vogel 9126ab6bfe3SJack F Vogel /** 9137d9119bdSJack F Vogel * e1000_set_eee_pchlan - Enable/disable EEE support 9147d9119bdSJack F Vogel * @hw: pointer to the HW structure 9157d9119bdSJack F Vogel * 9166ab6bfe3SJack F Vogel * Enable/disable EEE based on setting in dev_spec structure, the duplex of 9176ab6bfe3SJack F Vogel * the link and the EEE capabilities of the link partner. The LPI Control 9186ab6bfe3SJack F Vogel * register bits will remain set only if/when link is up. 9197609433eSJack F Vogel * 9207609433eSJack F Vogel * EEE LPI must not be asserted earlier than one second after link is up. 9217609433eSJack F Vogel * On 82579, EEE LPI should not be enabled until such time otherwise there 9227609433eSJack F Vogel * can be link issues with some switches. Other devices can have EEE LPI 9237609433eSJack F Vogel * enabled immediately upon link up since they have a timer in hardware which 9247609433eSJack F Vogel * prevents LPI from being asserted too early. 9257d9119bdSJack F Vogel **/ 9267609433eSJack F Vogel s32 e1000_set_eee_pchlan(struct e1000_hw *hw) 9277d9119bdSJack F Vogel { 9284dab5c37SJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 9296ab6bfe3SJack F Vogel s32 ret_val; 9307609433eSJack F Vogel u16 lpa, pcs_status, adv, adv_addr, lpi_ctrl, data; 9317d9119bdSJack F Vogel 9327d9119bdSJack F Vogel DEBUGFUNC("e1000_set_eee_pchlan"); 9337d9119bdSJack F Vogel 9347609433eSJack F Vogel switch (hw->phy.type) { 9357609433eSJack F Vogel case e1000_phy_82579: 9367609433eSJack F Vogel lpa = I82579_EEE_LP_ABILITY; 9377609433eSJack F Vogel pcs_status = I82579_EEE_PCS_STATUS; 9387609433eSJack F Vogel adv_addr = I82579_EEE_ADVERTISEMENT; 9397609433eSJack F Vogel break; 9407609433eSJack F Vogel case e1000_phy_i217: 9417609433eSJack F Vogel lpa = I217_EEE_LP_ABILITY; 9427609433eSJack F Vogel pcs_status = I217_EEE_PCS_STATUS; 9437609433eSJack F Vogel adv_addr = I217_EEE_ADVERTISEMENT; 9447609433eSJack F Vogel break; 9457609433eSJack F Vogel default: 9466ab6bfe3SJack F Vogel return E1000_SUCCESS; 9477609433eSJack F Vogel } 9487d9119bdSJack F Vogel 9496ab6bfe3SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 9507d9119bdSJack F Vogel if (ret_val) 9517d9119bdSJack F Vogel return ret_val; 9526ab6bfe3SJack F Vogel 9536ab6bfe3SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, I82579_LPI_CTRL, &lpi_ctrl); 9546ab6bfe3SJack F Vogel if (ret_val) 9556ab6bfe3SJack F Vogel goto release; 9566ab6bfe3SJack F Vogel 9576ab6bfe3SJack F Vogel /* Clear bits that enable EEE in various speeds */ 9586ab6bfe3SJack F Vogel lpi_ctrl &= ~I82579_LPI_CTRL_ENABLE_MASK; 9596ab6bfe3SJack F Vogel 9606ab6bfe3SJack F Vogel /* Enable EEE if not disabled by user */ 9616ab6bfe3SJack F Vogel if (!dev_spec->eee_disable) { 9626ab6bfe3SJack F Vogel /* Save off link partner's EEE ability */ 9636ab6bfe3SJack F Vogel ret_val = e1000_read_emi_reg_locked(hw, lpa, 9646ab6bfe3SJack F Vogel &dev_spec->eee_lp_ability); 9656ab6bfe3SJack F Vogel if (ret_val) 9666ab6bfe3SJack F Vogel goto release; 9676ab6bfe3SJack F Vogel 9687609433eSJack F Vogel /* Read EEE advertisement */ 9697609433eSJack F Vogel ret_val = e1000_read_emi_reg_locked(hw, adv_addr, &adv); 9707609433eSJack F Vogel if (ret_val) 9717609433eSJack F Vogel goto release; 9727609433eSJack F Vogel 9736ab6bfe3SJack F Vogel /* Enable EEE only for speeds in which the link partner is 9747609433eSJack F Vogel * EEE capable and for which we advertise EEE. 9756ab6bfe3SJack F Vogel */ 9767609433eSJack F Vogel if (adv & dev_spec->eee_lp_ability & I82579_EEE_1000_SUPPORTED) 9776ab6bfe3SJack F Vogel lpi_ctrl |= I82579_LPI_CTRL_1000_ENABLE; 9786ab6bfe3SJack F Vogel 9797609433eSJack F Vogel if (adv & dev_spec->eee_lp_ability & I82579_EEE_100_SUPPORTED) { 9806ab6bfe3SJack F Vogel hw->phy.ops.read_reg_locked(hw, PHY_LP_ABILITY, &data); 9816ab6bfe3SJack F Vogel if (data & NWAY_LPAR_100TX_FD_CAPS) 9826ab6bfe3SJack F Vogel lpi_ctrl |= I82579_LPI_CTRL_100_ENABLE; 9836ab6bfe3SJack F Vogel else 9846ab6bfe3SJack F Vogel /* EEE is not supported in 100Half, so ignore 9856ab6bfe3SJack F Vogel * partner's EEE in 100 ability if full-duplex 9866ab6bfe3SJack F Vogel * is not advertised. 9876ab6bfe3SJack F Vogel */ 9886ab6bfe3SJack F Vogel dev_spec->eee_lp_ability &= 9896ab6bfe3SJack F Vogel ~I82579_EEE_100_SUPPORTED; 9906ab6bfe3SJack F Vogel } 9917609433eSJack F Vogel } 9926ab6bfe3SJack F Vogel 9938cc64f1eSJack F Vogel if (hw->phy.type == e1000_phy_82579) { 9948cc64f1eSJack F Vogel ret_val = e1000_read_emi_reg_locked(hw, I82579_LPI_PLL_SHUT, 9958cc64f1eSJack F Vogel &data); 9968cc64f1eSJack F Vogel if (ret_val) 9978cc64f1eSJack F Vogel goto release; 9988cc64f1eSJack F Vogel 9998cc64f1eSJack F Vogel data &= ~I82579_LPI_100_PLL_SHUT; 10008cc64f1eSJack F Vogel ret_val = e1000_write_emi_reg_locked(hw, I82579_LPI_PLL_SHUT, 10018cc64f1eSJack F Vogel data); 10028cc64f1eSJack F Vogel } 10038cc64f1eSJack F Vogel 10046ab6bfe3SJack F Vogel /* R/Clr IEEE MMD 3.1 bits 11:10 - Tx/Rx LPI Received */ 10056ab6bfe3SJack F Vogel ret_val = e1000_read_emi_reg_locked(hw, pcs_status, &data); 10066ab6bfe3SJack F Vogel if (ret_val) 10076ab6bfe3SJack F Vogel goto release; 10086ab6bfe3SJack F Vogel 10096ab6bfe3SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, I82579_LPI_CTRL, lpi_ctrl); 10106ab6bfe3SJack F Vogel release: 10116ab6bfe3SJack F Vogel hw->phy.ops.release(hw); 10126ab6bfe3SJack F Vogel 10136ab6bfe3SJack F Vogel return ret_val; 10146ab6bfe3SJack F Vogel } 10156ab6bfe3SJack F Vogel 10166ab6bfe3SJack F Vogel /** 10176ab6bfe3SJack F Vogel * e1000_k1_workaround_lpt_lp - K1 workaround on Lynxpoint-LP 10186ab6bfe3SJack F Vogel * @hw: pointer to the HW structure 10196ab6bfe3SJack F Vogel * @link: link up bool flag 10206ab6bfe3SJack F Vogel * 10216ab6bfe3SJack F Vogel * When K1 is enabled for 1Gbps, the MAC can miss 2 DMA completion indications 10226ab6bfe3SJack F Vogel * preventing further DMA write requests. Workaround the issue by disabling 10236ab6bfe3SJack F Vogel * the de-assertion of the clock request when in 1Gpbs mode. 10247609433eSJack F Vogel * Also, set appropriate Tx re-transmission timeouts for 10 and 100Half link 10257609433eSJack F Vogel * speeds in order to avoid Tx hangs. 10266ab6bfe3SJack F Vogel **/ 10276ab6bfe3SJack F Vogel static s32 e1000_k1_workaround_lpt_lp(struct e1000_hw *hw, bool link) 10286ab6bfe3SJack F Vogel { 10296ab6bfe3SJack F Vogel u32 fextnvm6 = E1000_READ_REG(hw, E1000_FEXTNVM6); 10307609433eSJack F Vogel u32 status = E1000_READ_REG(hw, E1000_STATUS); 10316ab6bfe3SJack F Vogel s32 ret_val = E1000_SUCCESS; 10327609433eSJack F Vogel u16 reg; 10336ab6bfe3SJack F Vogel 10347609433eSJack F Vogel if (link && (status & E1000_STATUS_SPEED_1000)) { 10356ab6bfe3SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 10366ab6bfe3SJack F Vogel if (ret_val) 10376ab6bfe3SJack F Vogel return ret_val; 10386ab6bfe3SJack F Vogel 10396ab6bfe3SJack F Vogel ret_val = 10406ab6bfe3SJack F Vogel e1000_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG, 10417609433eSJack F Vogel ®); 10426ab6bfe3SJack F Vogel if (ret_val) 10436ab6bfe3SJack F Vogel goto release; 10446ab6bfe3SJack F Vogel 10456ab6bfe3SJack F Vogel ret_val = 10466ab6bfe3SJack F Vogel e1000_write_kmrn_reg_locked(hw, 10476ab6bfe3SJack F Vogel E1000_KMRNCTRLSTA_K1_CONFIG, 10487609433eSJack F Vogel reg & 10496ab6bfe3SJack F Vogel ~E1000_KMRNCTRLSTA_K1_ENABLE); 10506ab6bfe3SJack F Vogel if (ret_val) 10516ab6bfe3SJack F Vogel goto release; 10526ab6bfe3SJack F Vogel 10536ab6bfe3SJack F Vogel usec_delay(10); 10546ab6bfe3SJack F Vogel 10556ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM6, 10566ab6bfe3SJack F Vogel fextnvm6 | E1000_FEXTNVM6_REQ_PLL_CLK); 10576ab6bfe3SJack F Vogel 10586ab6bfe3SJack F Vogel ret_val = 10596ab6bfe3SJack F Vogel e1000_write_kmrn_reg_locked(hw, 10606ab6bfe3SJack F Vogel E1000_KMRNCTRLSTA_K1_CONFIG, 10617609433eSJack F Vogel reg); 10626ab6bfe3SJack F Vogel release: 10636ab6bfe3SJack F Vogel hw->phy.ops.release(hw); 10646ab6bfe3SJack F Vogel } else { 10656ab6bfe3SJack F Vogel /* clear FEXTNVM6 bit 8 on link down or 10/100 */ 10667609433eSJack F Vogel fextnvm6 &= ~E1000_FEXTNVM6_REQ_PLL_CLK; 10677609433eSJack F Vogel 1068c80429ceSEric Joyner if ((hw->phy.revision > 5) || !link || 1069c80429ceSEric Joyner ((status & E1000_STATUS_SPEED_100) && 10707609433eSJack F Vogel (status & E1000_STATUS_FD))) 10717609433eSJack F Vogel goto update_fextnvm6; 10727609433eSJack F Vogel 10737609433eSJack F Vogel ret_val = hw->phy.ops.read_reg(hw, I217_INBAND_CTRL, ®); 10747609433eSJack F Vogel if (ret_val) 10757609433eSJack F Vogel return ret_val; 10767609433eSJack F Vogel 10777609433eSJack F Vogel /* Clear link status transmit timeout */ 10787609433eSJack F Vogel reg &= ~I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_MASK; 10797609433eSJack F Vogel 10807609433eSJack F Vogel if (status & E1000_STATUS_SPEED_100) { 10817609433eSJack F Vogel /* Set inband Tx timeout to 5x10us for 100Half */ 10827609433eSJack F Vogel reg |= 5 << I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT; 10837609433eSJack F Vogel 10847609433eSJack F Vogel /* Do not extend the K1 entry latency for 100Half */ 10857609433eSJack F Vogel fextnvm6 &= ~E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION; 10867609433eSJack F Vogel } else { 10877609433eSJack F Vogel /* Set inband Tx timeout to 50x10us for 10Full/Half */ 10887609433eSJack F Vogel reg |= 50 << 10897609433eSJack F Vogel I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT; 10907609433eSJack F Vogel 10917609433eSJack F Vogel /* Extend the K1 entry latency for 10 Mbps */ 10927609433eSJack F Vogel fextnvm6 |= E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION; 10937609433eSJack F Vogel } 10947609433eSJack F Vogel 10957609433eSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, I217_INBAND_CTRL, reg); 10967609433eSJack F Vogel if (ret_val) 10977609433eSJack F Vogel return ret_val; 10987609433eSJack F Vogel 10997609433eSJack F Vogel update_fextnvm6: 11007609433eSJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM6, fextnvm6); 11016ab6bfe3SJack F Vogel } 11026ab6bfe3SJack F Vogel 11036ab6bfe3SJack F Vogel return ret_val; 11046ab6bfe3SJack F Vogel } 11056ab6bfe3SJack F Vogel 1106e373323fSSean Bruno static u64 e1000_ltr2ns(u16 ltr) 1107e373323fSSean Bruno { 1108e373323fSSean Bruno u32 value, scale; 1109e373323fSSean Bruno 1110e373323fSSean Bruno /* Determine the latency in nsec based on the LTR value & scale */ 1111e373323fSSean Bruno value = ltr & E1000_LTRV_VALUE_MASK; 1112e373323fSSean Bruno scale = (ltr & E1000_LTRV_SCALE_MASK) >> E1000_LTRV_SCALE_SHIFT; 1113e373323fSSean Bruno 111451569bd7SEric Joyner return value * (1ULL << (scale * E1000_LTRV_SCALE_FACTOR)); 1115e373323fSSean Bruno } 1116e373323fSSean Bruno 1117e373323fSSean Bruno /** 1118e373323fSSean Bruno * e1000_platform_pm_pch_lpt - Set platform power management values 1119e373323fSSean Bruno * @hw: pointer to the HW structure 1120e373323fSSean Bruno * @link: bool indicating link status 1121e373323fSSean Bruno * 1122e373323fSSean Bruno * Set the Latency Tolerance Reporting (LTR) values for the "PCIe-like" 1123e373323fSSean Bruno * GbE MAC in the Lynx Point PCH based on Rx buffer size and link speed 1124e373323fSSean Bruno * when link is up (which must not exceed the maximum latency supported 1125e373323fSSean Bruno * by the platform), otherwise specify there is no LTR requirement. 1126e373323fSSean Bruno * Unlike TRUE-PCIe devices which set the LTR maximum snoop/no-snoop 1127e373323fSSean Bruno * latencies in the LTR Extended Capability Structure in the PCIe Extended 1128e373323fSSean Bruno * Capability register set, on this device LTR is set by writing the 1129e373323fSSean Bruno * equivalent snoop/no-snoop latencies in the LTRV register in the MAC and 1130e373323fSSean Bruno * set the SEND bit to send an Intel On-chip System Fabric sideband (IOSF-SB) 1131e373323fSSean Bruno * message to the PMC. 1132e373323fSSean Bruno * 1133e373323fSSean Bruno * Use the LTR value to calculate the Optimized Buffer Flush/Fill (OBFF) 1134e373323fSSean Bruno * high-water mark. 1135e373323fSSean Bruno **/ 1136e373323fSSean Bruno static s32 e1000_platform_pm_pch_lpt(struct e1000_hw *hw, bool link) 1137e373323fSSean Bruno { 1138e373323fSSean Bruno u32 reg = link << (E1000_LTRV_REQ_SHIFT + E1000_LTRV_NOSNOOP_SHIFT) | 1139e373323fSSean Bruno link << E1000_LTRV_REQ_SHIFT | E1000_LTRV_SEND; 1140e373323fSSean Bruno u16 lat_enc = 0; /* latency encoded */ 1141e373323fSSean Bruno s32 obff_hwm = 0; 1142e373323fSSean Bruno 1143e373323fSSean Bruno DEBUGFUNC("e1000_platform_pm_pch_lpt"); 1144e373323fSSean Bruno 1145e373323fSSean Bruno if (link) { 1146e373323fSSean Bruno u16 speed, duplex, scale = 0; 1147e373323fSSean Bruno u16 max_snoop, max_nosnoop; 1148e373323fSSean Bruno u16 max_ltr_enc; /* max LTR latency encoded */ 1149e373323fSSean Bruno s64 lat_ns; 1150e373323fSSean Bruno s64 value; 1151e373323fSSean Bruno u32 rxa; 1152e373323fSSean Bruno 1153e373323fSSean Bruno if (!hw->mac.max_frame_size) { 1154e373323fSSean Bruno DEBUGOUT("max_frame_size not set.\n"); 1155e373323fSSean Bruno return -E1000_ERR_CONFIG; 1156e373323fSSean Bruno } 1157e373323fSSean Bruno 1158e373323fSSean Bruno hw->mac.ops.get_link_up_info(hw, &speed, &duplex); 1159e373323fSSean Bruno if (!speed) { 1160e373323fSSean Bruno DEBUGOUT("Speed not set.\n"); 1161e373323fSSean Bruno return -E1000_ERR_CONFIG; 1162e373323fSSean Bruno } 1163e373323fSSean Bruno 1164e373323fSSean Bruno /* Rx Packet Buffer Allocation size (KB) */ 1165e373323fSSean Bruno rxa = E1000_READ_REG(hw, E1000_PBA) & E1000_PBA_RXA_MASK; 1166e373323fSSean Bruno 1167e373323fSSean Bruno /* Determine the maximum latency tolerated by the device. 1168e373323fSSean Bruno * 1169e373323fSSean Bruno * Per the PCIe spec, the tolerated latencies are encoded as 1170e373323fSSean Bruno * a 3-bit encoded scale (only 0-5 are valid) multiplied by 1171e373323fSSean Bruno * a 10-bit value (0-1023) to provide a range from 1 ns to 1172e373323fSSean Bruno * 2^25*(2^10-1) ns. The scale is encoded as 0=2^0ns, 1173e373323fSSean Bruno * 1=2^5ns, 2=2^10ns,...5=2^25ns. 1174e373323fSSean Bruno */ 1175e373323fSSean Bruno lat_ns = ((s64)rxa * 1024 - 1176e373323fSSean Bruno (2 * (s64)hw->mac.max_frame_size)) * 8 * 1000; 1177e373323fSSean Bruno if (lat_ns < 0) 1178e373323fSSean Bruno lat_ns = 0; 1179e373323fSSean Bruno else 1180e373323fSSean Bruno lat_ns /= speed; 1181e373323fSSean Bruno value = lat_ns; 1182e373323fSSean Bruno 1183e373323fSSean Bruno while (value > E1000_LTRV_VALUE_MASK) { 1184e373323fSSean Bruno scale++; 1185e373323fSSean Bruno value = E1000_DIVIDE_ROUND_UP(value, (1 << 5)); 1186e373323fSSean Bruno } 1187e373323fSSean Bruno if (scale > E1000_LTRV_SCALE_MAX) { 1188e373323fSSean Bruno DEBUGOUT1("Invalid LTR latency scale %d\n", scale); 1189e373323fSSean Bruno return -E1000_ERR_CONFIG; 1190e373323fSSean Bruno } 1191e373323fSSean Bruno lat_enc = (u16)((scale << E1000_LTRV_SCALE_SHIFT) | value); 1192e373323fSSean Bruno 1193e373323fSSean Bruno /* Determine the maximum latency tolerated by the platform */ 1194e373323fSSean Bruno e1000_read_pci_cfg(hw, E1000_PCI_LTR_CAP_LPT, &max_snoop); 1195e373323fSSean Bruno e1000_read_pci_cfg(hw, E1000_PCI_LTR_CAP_LPT + 2, &max_nosnoop); 1196e373323fSSean Bruno max_ltr_enc = E1000_MAX(max_snoop, max_nosnoop); 1197e373323fSSean Bruno 1198e373323fSSean Bruno if (lat_enc > max_ltr_enc) { 1199e373323fSSean Bruno lat_enc = max_ltr_enc; 1200e373323fSSean Bruno lat_ns = e1000_ltr2ns(max_ltr_enc); 1201e373323fSSean Bruno } 1202e373323fSSean Bruno 1203e373323fSSean Bruno if (lat_ns) { 1204e373323fSSean Bruno lat_ns *= speed * 1000; 1205e373323fSSean Bruno lat_ns /= 8; 1206e373323fSSean Bruno lat_ns /= 1000000000; 1207e373323fSSean Bruno obff_hwm = (s32)(rxa - lat_ns); 1208e373323fSSean Bruno } 1209e373323fSSean Bruno if ((obff_hwm < 0) || (obff_hwm > E1000_SVT_OFF_HWM_MASK)) { 1210e373323fSSean Bruno DEBUGOUT1("Invalid high water mark %d\n", obff_hwm); 1211e373323fSSean Bruno return -E1000_ERR_CONFIG; 1212e373323fSSean Bruno } 1213e373323fSSean Bruno } 1214e373323fSSean Bruno 1215e373323fSSean Bruno /* Set Snoop and No-Snoop latencies the same */ 1216e373323fSSean Bruno reg |= lat_enc | (lat_enc << E1000_LTRV_NOSNOOP_SHIFT); 1217e373323fSSean Bruno E1000_WRITE_REG(hw, E1000_LTRV, reg); 1218e373323fSSean Bruno 1219e373323fSSean Bruno /* Set OBFF high water mark */ 1220e373323fSSean Bruno reg = E1000_READ_REG(hw, E1000_SVT) & ~E1000_SVT_OFF_HWM_MASK; 1221e373323fSSean Bruno reg |= obff_hwm; 1222e373323fSSean Bruno E1000_WRITE_REG(hw, E1000_SVT, reg); 1223e373323fSSean Bruno 1224e373323fSSean Bruno /* Enable OBFF */ 1225e373323fSSean Bruno reg = E1000_READ_REG(hw, E1000_SVCR); 1226e373323fSSean Bruno reg |= E1000_SVCR_OFF_EN; 1227e373323fSSean Bruno /* Always unblock interrupts to the CPU even when the system is 1228e373323fSSean Bruno * in OBFF mode. This ensures that small round-robin traffic 1229e373323fSSean Bruno * (like ping) does not get dropped or experience long latency. 1230e373323fSSean Bruno */ 1231e373323fSSean Bruno reg |= E1000_SVCR_OFF_MASKINT; 1232e373323fSSean Bruno E1000_WRITE_REG(hw, E1000_SVCR, reg); 1233e373323fSSean Bruno 1234e373323fSSean Bruno return E1000_SUCCESS; 1235e373323fSSean Bruno } 1236e373323fSSean Bruno 1237e373323fSSean Bruno /** 1238e373323fSSean Bruno * e1000_set_obff_timer_pch_lpt - Update Optimized Buffer Flush/Fill timer 1239e373323fSSean Bruno * @hw: pointer to the HW structure 1240e373323fSSean Bruno * @itr: interrupt throttling rate 1241e373323fSSean Bruno * 1242e373323fSSean Bruno * Configure OBFF with the updated interrupt rate. 1243e373323fSSean Bruno **/ 1244e373323fSSean Bruno static s32 e1000_set_obff_timer_pch_lpt(struct e1000_hw *hw, u32 itr) 1245e373323fSSean Bruno { 1246e373323fSSean Bruno u32 svcr; 1247e373323fSSean Bruno s32 timer; 1248e373323fSSean Bruno 1249e373323fSSean Bruno DEBUGFUNC("e1000_set_obff_timer_pch_lpt"); 1250e373323fSSean Bruno 1251e373323fSSean Bruno /* Convert ITR value into microseconds for OBFF timer */ 1252e373323fSSean Bruno timer = itr & E1000_ITR_MASK; 1253e373323fSSean Bruno timer = (timer * E1000_ITR_MULT) / 1000; 1254e373323fSSean Bruno 1255e373323fSSean Bruno if ((timer < 0) || (timer > E1000_ITR_MASK)) { 1256e373323fSSean Bruno DEBUGOUT1("Invalid OBFF timer %d\n", timer); 1257e373323fSSean Bruno return -E1000_ERR_CONFIG; 1258e373323fSSean Bruno } 1259e373323fSSean Bruno 1260e373323fSSean Bruno svcr = E1000_READ_REG(hw, E1000_SVCR); 1261e373323fSSean Bruno svcr &= ~E1000_SVCR_OFF_TIMER_MASK; 1262e373323fSSean Bruno svcr |= timer << E1000_SVCR_OFF_TIMER_SHIFT; 1263e373323fSSean Bruno E1000_WRITE_REG(hw, E1000_SVCR, svcr); 1264e373323fSSean Bruno 1265e373323fSSean Bruno return E1000_SUCCESS; 1266e373323fSSean Bruno } 1267e373323fSSean Bruno 12687d9119bdSJack F Vogel /** 12698cc64f1eSJack F Vogel * e1000_enable_ulp_lpt_lp - configure Ultra Low Power mode for LynxPoint-LP 12708cc64f1eSJack F Vogel * @hw: pointer to the HW structure 12718cc64f1eSJack F Vogel * @to_sx: boolean indicating a system power state transition to Sx 12728cc64f1eSJack F Vogel * 12738cc64f1eSJack F Vogel * When link is down, configure ULP mode to significantly reduce the power 12748cc64f1eSJack F Vogel * to the PHY. If on a Manageability Engine (ME) enabled system, tell the 12758cc64f1eSJack F Vogel * ME firmware to start the ULP configuration. If not on an ME enabled 12768cc64f1eSJack F Vogel * system, configure the ULP mode by software. 12778cc64f1eSJack F Vogel */ 12788cc64f1eSJack F Vogel s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx) 12798cc64f1eSJack F Vogel { 12808cc64f1eSJack F Vogel u32 mac_reg; 12818cc64f1eSJack F Vogel s32 ret_val = E1000_SUCCESS; 12828cc64f1eSJack F Vogel u16 phy_reg; 1283c80429ceSEric Joyner u16 oem_reg = 0; 12848cc64f1eSJack F Vogel 12858cc64f1eSJack F Vogel if ((hw->mac.type < e1000_pch_lpt) || 12868cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_LM) || 12878cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_V) || 12888cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_I218_LM2) || 12898cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_I218_V2) || 12908cc64f1eSJack F Vogel (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_on)) 12918cc64f1eSJack F Vogel return 0; 12928cc64f1eSJack F Vogel 12938cc64f1eSJack F Vogel if (!to_sx) { 12948cc64f1eSJack F Vogel int i = 0; 12958cc64f1eSJack F Vogel /* Poll up to 5 seconds for Cable Disconnected indication */ 12968cc64f1eSJack F Vogel while (!(E1000_READ_REG(hw, E1000_FEXT) & 12978cc64f1eSJack F Vogel E1000_FEXT_PHY_CABLE_DISCONNECTED)) { 12988cc64f1eSJack F Vogel /* Bail if link is re-acquired */ 12998cc64f1eSJack F Vogel if (E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU) 13008cc64f1eSJack F Vogel return -E1000_ERR_PHY; 13018cc64f1eSJack F Vogel if (i++ == 100) 13028cc64f1eSJack F Vogel break; 13038cc64f1eSJack F Vogel 13048cc64f1eSJack F Vogel msec_delay(50); 13058cc64f1eSJack F Vogel } 13068cc64f1eSJack F Vogel DEBUGOUT2("CABLE_DISCONNECTED %s set after %dmsec\n", 13078cc64f1eSJack F Vogel (E1000_READ_REG(hw, E1000_FEXT) & 13088cc64f1eSJack F Vogel E1000_FEXT_PHY_CABLE_DISCONNECTED) ? "" : "not", 13098cc64f1eSJack F Vogel i * 50); 1310*fc7682b1SKevin Bowling if (!(E1000_READ_REG(hw, E1000_FEXT) & 1311*fc7682b1SKevin Bowling E1000_FEXT_PHY_CABLE_DISCONNECTED)) 1312*fc7682b1SKevin Bowling return 0; 1313*fc7682b1SKevin Bowling } 1314*fc7682b1SKevin Bowling 1315*fc7682b1SKevin Bowling if (E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID) { 1316*fc7682b1SKevin Bowling /* Request ME configure ULP mode in the PHY */ 1317*fc7682b1SKevin Bowling mac_reg = E1000_READ_REG(hw, E1000_H2ME); 1318*fc7682b1SKevin Bowling mac_reg |= E1000_H2ME_ULP | E1000_H2ME_ENFORCE_SETTINGS; 1319*fc7682b1SKevin Bowling E1000_WRITE_REG(hw, E1000_H2ME, mac_reg); 1320*fc7682b1SKevin Bowling 1321*fc7682b1SKevin Bowling goto out; 13228cc64f1eSJack F Vogel } 13238cc64f1eSJack F Vogel 13248cc64f1eSJack F Vogel ret_val = hw->phy.ops.acquire(hw); 13258cc64f1eSJack F Vogel if (ret_val) 13268cc64f1eSJack F Vogel goto out; 13278cc64f1eSJack F Vogel 1328*fc7682b1SKevin Bowling /* During S0 Idle keep the phy in PCI-E mode */ 1329*fc7682b1SKevin Bowling if (hw->dev_spec.ich8lan.smbus_disable) 1330*fc7682b1SKevin Bowling goto skip_smbus; 1331*fc7682b1SKevin Bowling 13328cc64f1eSJack F Vogel /* Force SMBus mode in PHY */ 13338cc64f1eSJack F Vogel ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg); 13348cc64f1eSJack F Vogel if (ret_val) 13358cc64f1eSJack F Vogel goto release; 13368cc64f1eSJack F Vogel phy_reg |= CV_SMB_CTRL_FORCE_SMBUS; 13378cc64f1eSJack F Vogel e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg); 13388cc64f1eSJack F Vogel 13398cc64f1eSJack F Vogel /* Force SMBus mode in MAC */ 13408cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT); 13418cc64f1eSJack F Vogel mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS; 13428cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg); 13438cc64f1eSJack F Vogel 1344*fc7682b1SKevin Bowling /* Si workaround for ULP entry flow on i217/rev6 h/w. Enable 1345c80429ceSEric Joyner * LPLU and disable Gig speed when entering ULP 1346c80429ceSEric Joyner */ 1347c80429ceSEric Joyner if ((hw->phy.type == e1000_phy_i217) && (hw->phy.revision == 6)) { 1348c80429ceSEric Joyner ret_val = e1000_read_phy_reg_hv_locked(hw, HV_OEM_BITS, 1349c80429ceSEric Joyner &oem_reg); 1350c80429ceSEric Joyner if (ret_val) 1351c80429ceSEric Joyner goto release; 1352c80429ceSEric Joyner 1353c80429ceSEric Joyner phy_reg = oem_reg; 1354c80429ceSEric Joyner phy_reg |= HV_OEM_BITS_LPLU | HV_OEM_BITS_GBE_DIS; 1355c80429ceSEric Joyner 1356c80429ceSEric Joyner ret_val = e1000_write_phy_reg_hv_locked(hw, HV_OEM_BITS, 1357c80429ceSEric Joyner phy_reg); 1358c80429ceSEric Joyner 1359c80429ceSEric Joyner if (ret_val) 1360c80429ceSEric Joyner goto release; 1361c80429ceSEric Joyner } 1362c80429ceSEric Joyner 1363*fc7682b1SKevin Bowling skip_smbus: 1364*fc7682b1SKevin Bowling if (!to_sx) { 1365*fc7682b1SKevin Bowling /* Change the 'Link Status Change' interrupt to trigger 1366*fc7682b1SKevin Bowling * on 'Cable Status Change' 1367*fc7682b1SKevin Bowling */ 1368*fc7682b1SKevin Bowling ret_val = e1000_read_kmrn_reg_locked(hw, 1369*fc7682b1SKevin Bowling E1000_KMRNCTRLSTA_OP_MODES, 1370*fc7682b1SKevin Bowling &phy_reg); 1371*fc7682b1SKevin Bowling if (ret_val) 1372*fc7682b1SKevin Bowling goto release; 1373*fc7682b1SKevin Bowling phy_reg |= E1000_KMRNCTRLSTA_OP_MODES_LSC2CSC; 1374*fc7682b1SKevin Bowling e1000_write_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_OP_MODES, 1375*fc7682b1SKevin Bowling phy_reg); 1376*fc7682b1SKevin Bowling } 1377*fc7682b1SKevin Bowling 13788cc64f1eSJack F Vogel /* Set Inband ULP Exit, Reset to SMBus mode and 13798cc64f1eSJack F Vogel * Disable SMBus Release on PERST# in PHY 13808cc64f1eSJack F Vogel */ 13818cc64f1eSJack F Vogel ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg); 13828cc64f1eSJack F Vogel if (ret_val) 13838cc64f1eSJack F Vogel goto release; 13848cc64f1eSJack F Vogel phy_reg |= (I218_ULP_CONFIG1_RESET_TO_SMBUS | 13858cc64f1eSJack F Vogel I218_ULP_CONFIG1_DISABLE_SMB_PERST); 13868cc64f1eSJack F Vogel if (to_sx) { 13878cc64f1eSJack F Vogel if (E1000_READ_REG(hw, E1000_WUFC) & E1000_WUFC_LNKC) 13888cc64f1eSJack F Vogel phy_reg |= I218_ULP_CONFIG1_WOL_HOST; 1389c80429ceSEric Joyner else 1390c80429ceSEric Joyner phy_reg &= ~I218_ULP_CONFIG1_WOL_HOST; 13918cc64f1eSJack F Vogel 13928cc64f1eSJack F Vogel phy_reg |= I218_ULP_CONFIG1_STICKY_ULP; 1393c80429ceSEric Joyner phy_reg &= ~I218_ULP_CONFIG1_INBAND_EXIT; 13948cc64f1eSJack F Vogel } else { 13958cc64f1eSJack F Vogel phy_reg |= I218_ULP_CONFIG1_INBAND_EXIT; 1396c80429ceSEric Joyner phy_reg &= ~I218_ULP_CONFIG1_STICKY_ULP; 1397c80429ceSEric Joyner phy_reg &= ~I218_ULP_CONFIG1_WOL_HOST; 13988cc64f1eSJack F Vogel } 13998cc64f1eSJack F Vogel e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); 14008cc64f1eSJack F Vogel 14018cc64f1eSJack F Vogel /* Set Disable SMBus Release on PERST# in MAC */ 14028cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM7); 14038cc64f1eSJack F Vogel mac_reg |= E1000_FEXTNVM7_DISABLE_SMB_PERST; 14048cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM7, mac_reg); 14058cc64f1eSJack F Vogel 14068cc64f1eSJack F Vogel /* Commit ULP changes in PHY by starting auto ULP configuration */ 14078cc64f1eSJack F Vogel phy_reg |= I218_ULP_CONFIG1_START; 14088cc64f1eSJack F Vogel e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); 1409c80429ceSEric Joyner 1410*fc7682b1SKevin Bowling if (!to_sx) { 1411*fc7682b1SKevin Bowling /* Disable Tx so that the MAC doesn't send any (buffered) 1412*fc7682b1SKevin Bowling * packets to the PHY. 1413*fc7682b1SKevin Bowling */ 1414*fc7682b1SKevin Bowling mac_reg = E1000_READ_REG(hw, E1000_TCTL); 1415*fc7682b1SKevin Bowling mac_reg &= ~E1000_TCTL_EN; 1416*fc7682b1SKevin Bowling E1000_WRITE_REG(hw, E1000_TCTL, mac_reg); 1417*fc7682b1SKevin Bowling } 1418*fc7682b1SKevin Bowling 1419c80429ceSEric Joyner if ((hw->phy.type == e1000_phy_i217) && (hw->phy.revision == 6) && 1420c80429ceSEric Joyner to_sx && (E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) { 1421c80429ceSEric Joyner ret_val = e1000_write_phy_reg_hv_locked(hw, HV_OEM_BITS, 1422c80429ceSEric Joyner oem_reg); 1423c80429ceSEric Joyner if (ret_val) 1424c80429ceSEric Joyner goto release; 1425c80429ceSEric Joyner } 1426c80429ceSEric Joyner 14278cc64f1eSJack F Vogel release: 14288cc64f1eSJack F Vogel hw->phy.ops.release(hw); 14298cc64f1eSJack F Vogel out: 14308cc64f1eSJack F Vogel if (ret_val) 14318cc64f1eSJack F Vogel DEBUGOUT1("Error in ULP enable flow: %d\n", ret_val); 14328cc64f1eSJack F Vogel else 14338cc64f1eSJack F Vogel hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_on; 14348cc64f1eSJack F Vogel 14358cc64f1eSJack F Vogel return ret_val; 14368cc64f1eSJack F Vogel } 14378cc64f1eSJack F Vogel 14388cc64f1eSJack F Vogel /** 14398cc64f1eSJack F Vogel * e1000_disable_ulp_lpt_lp - unconfigure Ultra Low Power mode for LynxPoint-LP 14408cc64f1eSJack F Vogel * @hw: pointer to the HW structure 14418cc64f1eSJack F Vogel * @force: boolean indicating whether or not to force disabling ULP 14428cc64f1eSJack F Vogel * 14438cc64f1eSJack F Vogel * Un-configure ULP mode when link is up, the system is transitioned from 14448cc64f1eSJack F Vogel * Sx or the driver is unloaded. If on a Manageability Engine (ME) enabled 14458cc64f1eSJack F Vogel * system, poll for an indication from ME that ULP has been un-configured. 14468cc64f1eSJack F Vogel * If not on an ME enabled system, un-configure the ULP mode by software. 14478cc64f1eSJack F Vogel * 14488cc64f1eSJack F Vogel * During nominal operation, this function is called when link is acquired 14498cc64f1eSJack F Vogel * to disable ULP mode (force=FALSE); otherwise, for example when unloading 14508cc64f1eSJack F Vogel * the driver or during Sx->S0 transitions, this is called with force=TRUE 14518cc64f1eSJack F Vogel * to forcibly disable ULP. 1452*fc7682b1SKevin Bowling 1453*fc7682b1SKevin Bowling * When the cable is plugged in while the device is in D0, a Cable Status 1454*fc7682b1SKevin Bowling * Change interrupt is generated which causes this function to be called 1455*fc7682b1SKevin Bowling * to partially disable ULP mode and restart autonegotiation. This function 1456*fc7682b1SKevin Bowling * is then called again due to the resulting Link Status Change interrupt 1457*fc7682b1SKevin Bowling * to finish cleaning up after the ULP flow. 14588cc64f1eSJack F Vogel */ 14598cc64f1eSJack F Vogel s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force) 14608cc64f1eSJack F Vogel { 14618cc64f1eSJack F Vogel s32 ret_val = E1000_SUCCESS; 1462*fc7682b1SKevin Bowling u8 ulp_exit_timeout = 30; 14638cc64f1eSJack F Vogel u32 mac_reg; 14648cc64f1eSJack F Vogel u16 phy_reg; 14658cc64f1eSJack F Vogel int i = 0; 14668cc64f1eSJack F Vogel 14678cc64f1eSJack F Vogel if ((hw->mac.type < e1000_pch_lpt) || 14688cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_LM) || 14698cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_V) || 14708cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_I218_LM2) || 14718cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_I218_V2) || 14728cc64f1eSJack F Vogel (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_off)) 14738cc64f1eSJack F Vogel return 0; 14748cc64f1eSJack F Vogel 14758cc64f1eSJack F Vogel if (E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID) { 14768cc64f1eSJack F Vogel if (force) { 14778cc64f1eSJack F Vogel /* Request ME un-configure ULP mode in the PHY */ 14788cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_H2ME); 14798cc64f1eSJack F Vogel mac_reg &= ~E1000_H2ME_ULP; 14808cc64f1eSJack F Vogel mac_reg |= E1000_H2ME_ENFORCE_SETTINGS; 14818cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_H2ME, mac_reg); 14828cc64f1eSJack F Vogel } 14838cc64f1eSJack F Vogel 1484*fc7682b1SKevin Bowling if (hw->mac.type == e1000_pch_cnp) 1485*fc7682b1SKevin Bowling ulp_exit_timeout = 100; 1486*fc7682b1SKevin Bowling 14878cc64f1eSJack F Vogel while (E1000_READ_REG(hw, E1000_FWSM) & 14888cc64f1eSJack F Vogel E1000_FWSM_ULP_CFG_DONE) { 1489*fc7682b1SKevin Bowling if (i++ == ulp_exit_timeout) { 14908cc64f1eSJack F Vogel ret_val = -E1000_ERR_PHY; 14918cc64f1eSJack F Vogel goto out; 14928cc64f1eSJack F Vogel } 14938cc64f1eSJack F Vogel 14948cc64f1eSJack F Vogel msec_delay(10); 14958cc64f1eSJack F Vogel } 14968cc64f1eSJack F Vogel DEBUGOUT1("ULP_CONFIG_DONE cleared after %dmsec\n", i * 10); 14978cc64f1eSJack F Vogel 14988cc64f1eSJack F Vogel if (force) { 14998cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_H2ME); 15008cc64f1eSJack F Vogel mac_reg &= ~E1000_H2ME_ENFORCE_SETTINGS; 15018cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_H2ME, mac_reg); 15028cc64f1eSJack F Vogel } else { 15038cc64f1eSJack F Vogel /* Clear H2ME.ULP after ME ULP configuration */ 15048cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_H2ME); 15058cc64f1eSJack F Vogel mac_reg &= ~E1000_H2ME_ULP; 15068cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_H2ME, mac_reg); 1507*fc7682b1SKevin Bowling 1508*fc7682b1SKevin Bowling /* Restore link speed advertisements and restart 1509*fc7682b1SKevin Bowling * Auto-negotiation 1510*fc7682b1SKevin Bowling */ 1511*fc7682b1SKevin Bowling if (hw->mac.autoneg) { 1512*fc7682b1SKevin Bowling ret_val = e1000_phy_setup_autoneg(hw); 1513*fc7682b1SKevin Bowling if (ret_val) 1514*fc7682b1SKevin Bowling goto out; 1515*fc7682b1SKevin Bowling } else { 1516*fc7682b1SKevin Bowling ret_val = e1000_setup_copper_link_generic(hw); 1517*fc7682b1SKevin Bowling if (ret_val) 1518*fc7682b1SKevin Bowling goto out; 1519*fc7682b1SKevin Bowling } 1520*fc7682b1SKevin Bowling ret_val = e1000_oem_bits_config_ich8lan(hw, true); 15218cc64f1eSJack F Vogel } 15228cc64f1eSJack F Vogel 15238cc64f1eSJack F Vogel goto out; 15248cc64f1eSJack F Vogel } 15258cc64f1eSJack F Vogel 15268cc64f1eSJack F Vogel ret_val = hw->phy.ops.acquire(hw); 15278cc64f1eSJack F Vogel if (ret_val) 15288cc64f1eSJack F Vogel goto out; 15298cc64f1eSJack F Vogel 1530*fc7682b1SKevin Bowling /* Revert the change to the 'Link Status Change' 1531*fc7682b1SKevin Bowling * interrupt to trigger on 'Cable Status Change' 1532*fc7682b1SKevin Bowling */ 1533*fc7682b1SKevin Bowling ret_val = e1000_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_OP_MODES, 1534*fc7682b1SKevin Bowling &phy_reg); 1535*fc7682b1SKevin Bowling if (ret_val) 1536*fc7682b1SKevin Bowling goto release; 1537*fc7682b1SKevin Bowling phy_reg &= ~E1000_KMRNCTRLSTA_OP_MODES_LSC2CSC; 1538*fc7682b1SKevin Bowling e1000_write_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_OP_MODES, phy_reg); 1539*fc7682b1SKevin Bowling 15408cc64f1eSJack F Vogel if (force) 15418cc64f1eSJack F Vogel /* Toggle LANPHYPC Value bit */ 15428cc64f1eSJack F Vogel e1000_toggle_lanphypc_pch_lpt(hw); 15438cc64f1eSJack F Vogel 15448cc64f1eSJack F Vogel /* Unforce SMBus mode in PHY */ 15458cc64f1eSJack F Vogel ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg); 15468cc64f1eSJack F Vogel if (ret_val) { 15478cc64f1eSJack F Vogel /* The MAC might be in PCIe mode, so temporarily force to 15488cc64f1eSJack F Vogel * SMBus mode in order to access the PHY. 15498cc64f1eSJack F Vogel */ 15508cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT); 15518cc64f1eSJack F Vogel mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS; 15528cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg); 15538cc64f1eSJack F Vogel 15548cc64f1eSJack F Vogel msec_delay(50); 15558cc64f1eSJack F Vogel 15568cc64f1eSJack F Vogel ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, 15578cc64f1eSJack F Vogel &phy_reg); 15588cc64f1eSJack F Vogel if (ret_val) 15598cc64f1eSJack F Vogel goto release; 15608cc64f1eSJack F Vogel } 15618cc64f1eSJack F Vogel phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS; 15628cc64f1eSJack F Vogel e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg); 15638cc64f1eSJack F Vogel 15648cc64f1eSJack F Vogel /* Unforce SMBus mode in MAC */ 15658cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT); 15668cc64f1eSJack F Vogel mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS; 15678cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg); 15688cc64f1eSJack F Vogel 15698cc64f1eSJack F Vogel /* When ULP mode was previously entered, K1 was disabled by the 15708cc64f1eSJack F Vogel * hardware. Re-Enable K1 in the PHY when exiting ULP. 15718cc64f1eSJack F Vogel */ 15728cc64f1eSJack F Vogel ret_val = e1000_read_phy_reg_hv_locked(hw, HV_PM_CTRL, &phy_reg); 15738cc64f1eSJack F Vogel if (ret_val) 15748cc64f1eSJack F Vogel goto release; 15758cc64f1eSJack F Vogel phy_reg |= HV_PM_CTRL_K1_ENABLE; 15768cc64f1eSJack F Vogel e1000_write_phy_reg_hv_locked(hw, HV_PM_CTRL, phy_reg); 15778cc64f1eSJack F Vogel 15788cc64f1eSJack F Vogel /* Clear ULP enabled configuration */ 15798cc64f1eSJack F Vogel ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg); 15808cc64f1eSJack F Vogel if (ret_val) 15818cc64f1eSJack F Vogel goto release; 1582*fc7682b1SKevin Bowling /* CSC interrupt received due to ULP Indication */ 1583*fc7682b1SKevin Bowling if ((phy_reg & I218_ULP_CONFIG1_IND) || force) { 15848cc64f1eSJack F Vogel phy_reg &= ~(I218_ULP_CONFIG1_IND | 15858cc64f1eSJack F Vogel I218_ULP_CONFIG1_STICKY_ULP | 15868cc64f1eSJack F Vogel I218_ULP_CONFIG1_RESET_TO_SMBUS | 15878cc64f1eSJack F Vogel I218_ULP_CONFIG1_WOL_HOST | 15888cc64f1eSJack F Vogel I218_ULP_CONFIG1_INBAND_EXIT | 1589c80429ceSEric Joyner I218_ULP_CONFIG1_EN_ULP_LANPHYPC | 1590c80429ceSEric Joyner I218_ULP_CONFIG1_DIS_CLR_STICKY_ON_PERST | 15918cc64f1eSJack F Vogel I218_ULP_CONFIG1_DISABLE_SMB_PERST); 15928cc64f1eSJack F Vogel e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); 15938cc64f1eSJack F Vogel 15948cc64f1eSJack F Vogel /* Commit ULP changes by starting auto ULP configuration */ 15958cc64f1eSJack F Vogel phy_reg |= I218_ULP_CONFIG1_START; 15968cc64f1eSJack F Vogel e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); 15978cc64f1eSJack F Vogel 15988cc64f1eSJack F Vogel /* Clear Disable SMBus Release on PERST# in MAC */ 15998cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM7); 16008cc64f1eSJack F Vogel mac_reg &= ~E1000_FEXTNVM7_DISABLE_SMB_PERST; 16018cc64f1eSJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM7, mac_reg); 16028cc64f1eSJack F Vogel 1603*fc7682b1SKevin Bowling if (!force) { 1604*fc7682b1SKevin Bowling hw->phy.ops.release(hw); 1605*fc7682b1SKevin Bowling 1606*fc7682b1SKevin Bowling if (hw->mac.autoneg) 1607*fc7682b1SKevin Bowling e1000_phy_setup_autoneg(hw); 1608*fc7682b1SKevin Bowling else 1609*fc7682b1SKevin Bowling e1000_setup_copper_link_generic(hw); 1610*fc7682b1SKevin Bowling 1611*fc7682b1SKevin Bowling e1000_sw_lcd_config_ich8lan(hw); 1612*fc7682b1SKevin Bowling 1613*fc7682b1SKevin Bowling e1000_oem_bits_config_ich8lan(hw, true); 1614*fc7682b1SKevin Bowling 1615*fc7682b1SKevin Bowling /* Set ULP state to unknown and return non-zero to 1616*fc7682b1SKevin Bowling * indicate no link (yet) and re-enter on the next LSC 1617*fc7682b1SKevin Bowling * to finish disabling ULP flow. 1618*fc7682b1SKevin Bowling */ 1619*fc7682b1SKevin Bowling hw->dev_spec.ich8lan.ulp_state = 1620*fc7682b1SKevin Bowling e1000_ulp_state_unknown; 1621*fc7682b1SKevin Bowling 1622*fc7682b1SKevin Bowling return 1; 1623*fc7682b1SKevin Bowling } 1624*fc7682b1SKevin Bowling } 1625*fc7682b1SKevin Bowling 1626*fc7682b1SKevin Bowling /* Re-enable Tx */ 1627*fc7682b1SKevin Bowling mac_reg = E1000_READ_REG(hw, E1000_TCTL); 1628*fc7682b1SKevin Bowling mac_reg |= E1000_TCTL_EN; 1629*fc7682b1SKevin Bowling E1000_WRITE_REG(hw, E1000_TCTL, mac_reg); 1630*fc7682b1SKevin Bowling 16318cc64f1eSJack F Vogel release: 16328cc64f1eSJack F Vogel hw->phy.ops.release(hw); 16338cc64f1eSJack F Vogel if (force) { 16348cc64f1eSJack F Vogel hw->phy.ops.reset(hw); 16358cc64f1eSJack F Vogel msec_delay(50); 16368cc64f1eSJack F Vogel } 16378cc64f1eSJack F Vogel out: 16388cc64f1eSJack F Vogel if (ret_val) 16398cc64f1eSJack F Vogel DEBUGOUT1("Error in ULP disable flow: %d\n", ret_val); 16408cc64f1eSJack F Vogel else 16418cc64f1eSJack F Vogel hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_off; 16428cc64f1eSJack F Vogel 16438cc64f1eSJack F Vogel return ret_val; 16448cc64f1eSJack F Vogel } 16458cc64f1eSJack F Vogel 16468cc64f1eSJack F Vogel /** 16474edd8523SJack F Vogel * e1000_check_for_copper_link_ich8lan - Check for link (Copper) 16484edd8523SJack F Vogel * @hw: pointer to the HW structure 16494edd8523SJack F Vogel * 16504edd8523SJack F Vogel * Checks to see of the link status of the hardware has changed. If a 16514edd8523SJack F Vogel * change in link status has been detected, then we read the PHY registers 16524edd8523SJack F Vogel * to get the current speed/duplex if link exists. 16534edd8523SJack F Vogel **/ 16544edd8523SJack F Vogel static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) 16554edd8523SJack F Vogel { 16564edd8523SJack F Vogel struct e1000_mac_info *mac = &hw->mac; 1657c80429ceSEric Joyner s32 ret_val, tipg_reg = 0; 1658c80429ceSEric Joyner u16 emi_addr, emi_val = 0; 1659*fc7682b1SKevin Bowling bool link = false; 16604dab5c37SJack F Vogel u16 phy_reg; 16614edd8523SJack F Vogel 16624edd8523SJack F Vogel DEBUGFUNC("e1000_check_for_copper_link_ich8lan"); 16634edd8523SJack F Vogel 16646ab6bfe3SJack F Vogel /* We only want to go out to the PHY registers to see if Auto-Neg 16654edd8523SJack F Vogel * has completed and/or if our link status has changed. The 16664edd8523SJack F Vogel * get_link_status flag is set upon receiving a Link Status 16674edd8523SJack F Vogel * Change or Rx Sequence Error interrupt. 16684edd8523SJack F Vogel */ 16696ab6bfe3SJack F Vogel if (!mac->get_link_status) 16706ab6bfe3SJack F Vogel return E1000_SUCCESS; 16714edd8523SJack F Vogel 1672*fc7682b1SKevin Bowling if ((hw->mac.type < e1000_pch_lpt) || 1673*fc7682b1SKevin Bowling (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_LM) || 1674*fc7682b1SKevin Bowling (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_V)) { 16756ab6bfe3SJack F Vogel /* First we want to see if the MII Status Register reports 16764edd8523SJack F Vogel * link. If so, then we want to get the current speed/duplex 16774edd8523SJack F Vogel * of the PHY. 16784edd8523SJack F Vogel */ 16794edd8523SJack F Vogel ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); 16804edd8523SJack F Vogel if (ret_val) 16816ab6bfe3SJack F Vogel return ret_val; 1682*fc7682b1SKevin Bowling } else { 1683*fc7682b1SKevin Bowling /* Check the MAC's STATUS register to determine link state 1684*fc7682b1SKevin Bowling * since the PHY could be inaccessible while in ULP mode. 1685*fc7682b1SKevin Bowling */ 1686*fc7682b1SKevin Bowling link = !!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU); 1687*fc7682b1SKevin Bowling if (link) 1688*fc7682b1SKevin Bowling ret_val = e1000_disable_ulp_lpt_lp(hw, false); 1689*fc7682b1SKevin Bowling else 1690*fc7682b1SKevin Bowling ret_val = e1000_enable_ulp_lpt_lp(hw, false); 1691*fc7682b1SKevin Bowling if (ret_val) 1692*fc7682b1SKevin Bowling return ret_val; 1693*fc7682b1SKevin Bowling } 16944edd8523SJack F Vogel 16954edd8523SJack F Vogel if (hw->mac.type == e1000_pchlan) { 16964edd8523SJack F Vogel ret_val = e1000_k1_gig_workaround_hv(hw, link); 16974edd8523SJack F Vogel if (ret_val) 16986ab6bfe3SJack F Vogel return ret_val; 16994edd8523SJack F Vogel } 17004edd8523SJack F Vogel 17018cc64f1eSJack F Vogel /* When connected at 10Mbps half-duplex, some parts are excessively 17026ab6bfe3SJack F Vogel * aggressive resulting in many collisions. To avoid this, increase 17036ab6bfe3SJack F Vogel * the IPG and reduce Rx latency in the PHY. 17046ab6bfe3SJack F Vogel */ 1705295df609SEric Joyner if ((hw->mac.type >= e1000_pch2lan) && link) { 1706c80429ceSEric Joyner u16 speed, duplex; 17078cc64f1eSJack F Vogel 1708c80429ceSEric Joyner e1000_get_speed_and_duplex_copper_generic(hw, &speed, &duplex); 1709c80429ceSEric Joyner tipg_reg = E1000_READ_REG(hw, E1000_TIPG); 1710c80429ceSEric Joyner tipg_reg &= ~E1000_TIPG_IPGT_MASK; 17116ab6bfe3SJack F Vogel 1712c80429ceSEric Joyner if (duplex == HALF_DUPLEX && speed == SPEED_10) { 1713c80429ceSEric Joyner tipg_reg |= 0xFF; 17146ab6bfe3SJack F Vogel /* Reduce Rx latency in analog PHY */ 1715c80429ceSEric Joyner emi_val = 0; 1716295df609SEric Joyner } else if (hw->mac.type >= e1000_pch_spt && 1717c80429ceSEric Joyner duplex == FULL_DUPLEX && speed != SPEED_1000) { 1718c80429ceSEric Joyner tipg_reg |= 0xC; 1719c80429ceSEric Joyner emi_val = 1; 1720c80429ceSEric Joyner } else { 1721c80429ceSEric Joyner /* Roll back the default values */ 1722c80429ceSEric Joyner tipg_reg |= 0x08; 1723c80429ceSEric Joyner emi_val = 1; 1724c80429ceSEric Joyner } 1725c80429ceSEric Joyner 1726c80429ceSEric Joyner E1000_WRITE_REG(hw, E1000_TIPG, tipg_reg); 1727c80429ceSEric Joyner 17286ab6bfe3SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 17296ab6bfe3SJack F Vogel if (ret_val) 17306ab6bfe3SJack F Vogel return ret_val; 17316ab6bfe3SJack F Vogel 17328cc64f1eSJack F Vogel if (hw->mac.type == e1000_pch2lan) 17338cc64f1eSJack F Vogel emi_addr = I82579_RX_CONFIG; 17348cc64f1eSJack F Vogel else 17358cc64f1eSJack F Vogel emi_addr = I217_RX_CONFIG; 1736c80429ceSEric Joyner ret_val = e1000_write_emi_reg_locked(hw, emi_addr, emi_val); 17376ab6bfe3SJack F Vogel 1738295df609SEric Joyner 1739295df609SEric Joyner if (hw->mac.type >= e1000_pch_lpt) { 1740c80429ceSEric Joyner hw->phy.ops.read_reg_locked(hw, I217_PLL_CLOCK_GATE_REG, 1741c80429ceSEric Joyner &phy_reg); 1742c80429ceSEric Joyner phy_reg &= ~I217_PLL_CLOCK_GATE_MASK; 1743c80429ceSEric Joyner if (speed == SPEED_100 || speed == SPEED_10) 1744c80429ceSEric Joyner phy_reg |= 0x3E8; 1745c80429ceSEric Joyner else 1746c80429ceSEric Joyner phy_reg |= 0xFA; 1747c80429ceSEric Joyner hw->phy.ops.write_reg_locked(hw, 1748c80429ceSEric Joyner I217_PLL_CLOCK_GATE_REG, 1749c80429ceSEric Joyner phy_reg); 1750e760e292SSean Bruno 1751e760e292SSean Bruno if (speed == SPEED_1000) { 1752e760e292SSean Bruno hw->phy.ops.read_reg_locked(hw, HV_PM_CTRL, 1753e760e292SSean Bruno &phy_reg); 1754e760e292SSean Bruno 1755e760e292SSean Bruno phy_reg |= HV_PM_CTRL_K1_CLK_REQ; 1756e760e292SSean Bruno 1757e760e292SSean Bruno hw->phy.ops.write_reg_locked(hw, HV_PM_CTRL, 1758e760e292SSean Bruno phy_reg); 1759e760e292SSean Bruno } 1760c80429ceSEric Joyner } 17616ab6bfe3SJack F Vogel hw->phy.ops.release(hw); 17626ab6bfe3SJack F Vogel 17636ab6bfe3SJack F Vogel if (ret_val) 17646ab6bfe3SJack F Vogel return ret_val; 1765c80429ceSEric Joyner 1766295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt) { 1767c80429ceSEric Joyner u16 data; 1768c80429ceSEric Joyner u16 ptr_gap; 1769c80429ceSEric Joyner 1770c80429ceSEric Joyner if (speed == SPEED_1000) { 1771c80429ceSEric Joyner ret_val = hw->phy.ops.acquire(hw); 1772c80429ceSEric Joyner if (ret_val) 1773c80429ceSEric Joyner return ret_val; 1774c80429ceSEric Joyner 1775c80429ceSEric Joyner ret_val = hw->phy.ops.read_reg_locked(hw, 1776c80429ceSEric Joyner PHY_REG(776, 20), 1777c80429ceSEric Joyner &data); 1778c80429ceSEric Joyner if (ret_val) { 1779c80429ceSEric Joyner hw->phy.ops.release(hw); 1780c80429ceSEric Joyner return ret_val; 17816ab6bfe3SJack F Vogel } 1782c80429ceSEric Joyner 1783c80429ceSEric Joyner ptr_gap = (data & (0x3FF << 2)) >> 2; 1784c80429ceSEric Joyner if (ptr_gap < 0x18) { 1785c80429ceSEric Joyner data &= ~(0x3FF << 2); 1786c80429ceSEric Joyner data |= (0x18 << 2); 1787c80429ceSEric Joyner ret_val = 1788c80429ceSEric Joyner hw->phy.ops.write_reg_locked(hw, 1789c80429ceSEric Joyner PHY_REG(776, 20), data); 1790c80429ceSEric Joyner } 1791c80429ceSEric Joyner hw->phy.ops.release(hw); 1792c80429ceSEric Joyner if (ret_val) 1793c80429ceSEric Joyner return ret_val; 1794c80429ceSEric Joyner } else { 1795c80429ceSEric Joyner ret_val = hw->phy.ops.acquire(hw); 1796c80429ceSEric Joyner if (ret_val) 1797c80429ceSEric Joyner return ret_val; 1798c80429ceSEric Joyner 1799c80429ceSEric Joyner ret_val = hw->phy.ops.write_reg_locked(hw, 1800c80429ceSEric Joyner PHY_REG(776, 20), 1801c80429ceSEric Joyner 0xC023); 1802c80429ceSEric Joyner hw->phy.ops.release(hw); 1803c80429ceSEric Joyner if (ret_val) 1804c80429ceSEric Joyner return ret_val; 1805c80429ceSEric Joyner 1806c80429ceSEric Joyner } 1807c80429ceSEric Joyner } 1808c80429ceSEric Joyner } 1809c80429ceSEric Joyner 1810c80429ceSEric Joyner /* I217 Packet Loss issue: 1811c80429ceSEric Joyner * ensure that FEXTNVM4 Beacon Duration is set correctly 1812c80429ceSEric Joyner * on power up. 1813c80429ceSEric Joyner * Set the Beacon Duration for I217 to 8 usec 1814c80429ceSEric Joyner */ 1815295df609SEric Joyner if (hw->mac.type >= e1000_pch_lpt) { 1816c80429ceSEric Joyner u32 mac_reg; 1817c80429ceSEric Joyner 1818c80429ceSEric Joyner mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM4); 1819c80429ceSEric Joyner mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK; 1820c80429ceSEric Joyner mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_8USEC; 1821c80429ceSEric Joyner E1000_WRITE_REG(hw, E1000_FEXTNVM4, mac_reg); 18226ab6bfe3SJack F Vogel } 18236ab6bfe3SJack F Vogel 18246ab6bfe3SJack F Vogel /* Work-around I218 hang issue */ 18256ab6bfe3SJack F Vogel if ((hw->device_id == E1000_DEV_ID_PCH_LPTLP_I218_LM) || 18268cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_LPTLP_I218_V) || 18278cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_I218_LM3) || 18288cc64f1eSJack F Vogel (hw->device_id == E1000_DEV_ID_PCH_I218_V3)) { 18296ab6bfe3SJack F Vogel ret_val = e1000_k1_workaround_lpt_lp(hw, link); 18306ab6bfe3SJack F Vogel if (ret_val) 18316ab6bfe3SJack F Vogel return ret_val; 18326ab6bfe3SJack F Vogel } 1833295df609SEric Joyner if (hw->mac.type >= e1000_pch_lpt) { 1834e373323fSSean Bruno /* Set platform power management values for 1835e373323fSSean Bruno * Latency Tolerance Reporting (LTR) 1836e373323fSSean Bruno * Optimized Buffer Flush/Fill (OBFF) 1837e373323fSSean Bruno */ 1838e373323fSSean Bruno ret_val = e1000_platform_pm_pch_lpt(hw, link); 1839e373323fSSean Bruno if (ret_val) 1840e373323fSSean Bruno return ret_val; 1841e373323fSSean Bruno } 1842e373323fSSean Bruno 18436ab6bfe3SJack F Vogel /* Clear link partner's EEE ability */ 18446ab6bfe3SJack F Vogel hw->dev_spec.ich8lan.eee_lp_ability = 0; 18456ab6bfe3SJack F Vogel 1846*fc7682b1SKevin Bowling /* Configure K0s minimum time */ 1847*fc7682b1SKevin Bowling if (hw->mac.type >= e1000_pch_lpt) { 1848*fc7682b1SKevin Bowling e1000_configure_k0s_lpt(hw, K1_ENTRY_LATENCY, K1_MIN_TIME); 1849*fc7682b1SKevin Bowling } 1850*fc7682b1SKevin Bowling 1851295df609SEric Joyner if (hw->mac.type >= e1000_pch_lpt) { 1852c80429ceSEric Joyner u32 fextnvm6 = E1000_READ_REG(hw, E1000_FEXTNVM6); 1853c80429ceSEric Joyner 1854295df609SEric Joyner if (hw->mac.type == e1000_pch_spt) { 1855295df609SEric Joyner /* FEXTNVM6 K1-off workaround - for SPT only */ 1856295df609SEric Joyner u32 pcieanacfg = E1000_READ_REG(hw, E1000_PCIEANACFG); 1857295df609SEric Joyner 1858295df609SEric Joyner if (pcieanacfg & E1000_FEXTNVM6_K1_OFF_ENABLE) 1859c80429ceSEric Joyner fextnvm6 |= E1000_FEXTNVM6_K1_OFF_ENABLE; 1860c80429ceSEric Joyner else 1861c80429ceSEric Joyner fextnvm6 &= ~E1000_FEXTNVM6_K1_OFF_ENABLE; 1862295df609SEric Joyner } 1863295df609SEric Joyner 1864295df609SEric Joyner if (hw->dev_spec.ich8lan.disable_k1_off == TRUE) 1865295df609SEric Joyner fextnvm6 &= ~E1000_FEXTNVM6_K1_OFF_ENABLE; 1866c80429ceSEric Joyner 1867c80429ceSEric Joyner E1000_WRITE_REG(hw, E1000_FEXTNVM6, fextnvm6); 1868c80429ceSEric Joyner } 1869c80429ceSEric Joyner 18704edd8523SJack F Vogel if (!link) 18716ab6bfe3SJack F Vogel return E1000_SUCCESS; /* No link detected */ 18724edd8523SJack F Vogel 18734edd8523SJack F Vogel mac->get_link_status = FALSE; 18744edd8523SJack F Vogel 18754dab5c37SJack F Vogel switch (hw->mac.type) { 18764dab5c37SJack F Vogel case e1000_pch2lan: 18774dab5c37SJack F Vogel ret_val = e1000_k1_workaround_lv(hw); 18784dab5c37SJack F Vogel if (ret_val) 18796ab6bfe3SJack F Vogel return ret_val; 18804dab5c37SJack F Vogel /* fall-thru */ 18814dab5c37SJack F Vogel case e1000_pchlan: 18824edd8523SJack F Vogel if (hw->phy.type == e1000_phy_82578) { 18834edd8523SJack F Vogel ret_val = e1000_link_stall_workaround_hv(hw); 18844edd8523SJack F Vogel if (ret_val) 18856ab6bfe3SJack F Vogel return ret_val; 18864edd8523SJack F Vogel } 18874edd8523SJack F Vogel 18886ab6bfe3SJack F Vogel /* Workaround for PCHx parts in half-duplex: 18894dab5c37SJack F Vogel * Set the number of preambles removed from the packet 18904dab5c37SJack F Vogel * when it is passed from the PHY to the MAC to prevent 18914dab5c37SJack F Vogel * the MAC from misinterpreting the packet type. 18924dab5c37SJack F Vogel */ 18934dab5c37SJack F Vogel hw->phy.ops.read_reg(hw, HV_KMRN_FIFO_CTRLSTA, &phy_reg); 18944dab5c37SJack F Vogel phy_reg &= ~HV_KMRN_FIFO_CTRLSTA_PREAMBLE_MASK; 18954dab5c37SJack F Vogel 18964dab5c37SJack F Vogel if ((E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_FD) != 18974dab5c37SJack F Vogel E1000_STATUS_FD) 18984dab5c37SJack F Vogel phy_reg |= (1 << HV_KMRN_FIFO_CTRLSTA_PREAMBLE_SHIFT); 18994dab5c37SJack F Vogel 19004dab5c37SJack F Vogel hw->phy.ops.write_reg(hw, HV_KMRN_FIFO_CTRLSTA, phy_reg); 19014dab5c37SJack F Vogel break; 19024dab5c37SJack F Vogel default: 19034dab5c37SJack F Vogel break; 19047d9119bdSJack F Vogel } 19057d9119bdSJack F Vogel 19066ab6bfe3SJack F Vogel /* Check if there was DownShift, must be checked 19074edd8523SJack F Vogel * immediately after link-up 19084edd8523SJack F Vogel */ 19094edd8523SJack F Vogel e1000_check_downshift_generic(hw); 19104edd8523SJack F Vogel 19117d9119bdSJack F Vogel /* Enable/Disable EEE after link up */ 19127609433eSJack F Vogel if (hw->phy.type > e1000_phy_82579) { 19137d9119bdSJack F Vogel ret_val = e1000_set_eee_pchlan(hw); 19147d9119bdSJack F Vogel if (ret_val) 19156ab6bfe3SJack F Vogel return ret_val; 19167609433eSJack F Vogel } 19177d9119bdSJack F Vogel 19186ab6bfe3SJack F Vogel /* If we are forcing speed/duplex, then we simply return since 19194edd8523SJack F Vogel * we have already determined whether we have link or not. 19204edd8523SJack F Vogel */ 19216ab6bfe3SJack F Vogel if (!mac->autoneg) 19226ab6bfe3SJack F Vogel return -E1000_ERR_CONFIG; 19234edd8523SJack F Vogel 19246ab6bfe3SJack F Vogel /* Auto-Neg is enabled. Auto Speed Detection takes care 19254edd8523SJack F Vogel * of MAC speed/duplex configuration. So we only need to 19264edd8523SJack F Vogel * configure Collision Distance in the MAC. 19274edd8523SJack F Vogel */ 19286ab6bfe3SJack F Vogel mac->ops.config_collision_dist(hw); 19294edd8523SJack F Vogel 19306ab6bfe3SJack F Vogel /* Configure Flow Control now that Auto-Neg has completed. 19314edd8523SJack F Vogel * First, we need to restore the desired flow control 19324edd8523SJack F Vogel * settings because we may have had to re-autoneg with a 19334edd8523SJack F Vogel * different link partner. 19344edd8523SJack F Vogel */ 19354edd8523SJack F Vogel ret_val = e1000_config_fc_after_link_up_generic(hw); 19364edd8523SJack F Vogel if (ret_val) 19374edd8523SJack F Vogel DEBUGOUT("Error configuring flow control\n"); 19384edd8523SJack F Vogel 19394edd8523SJack F Vogel return ret_val; 19404edd8523SJack F Vogel } 19414edd8523SJack F Vogel 19424edd8523SJack F Vogel /** 19438cfa0ad2SJack F Vogel * e1000_init_function_pointers_ich8lan - Initialize ICH8 function pointers 19448cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 19458cfa0ad2SJack F Vogel * 19468cfa0ad2SJack F Vogel * Initialize family-specific function pointers for PHY, MAC, and NVM. 19478cfa0ad2SJack F Vogel **/ 19488cfa0ad2SJack F Vogel void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw) 19498cfa0ad2SJack F Vogel { 19508cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_function_pointers_ich8lan"); 19518cfa0ad2SJack F Vogel 19528cfa0ad2SJack F Vogel hw->mac.ops.init_params = e1000_init_mac_params_ich8lan; 19538cfa0ad2SJack F Vogel hw->nvm.ops.init_params = e1000_init_nvm_params_ich8lan; 19549d81738fSJack F Vogel switch (hw->mac.type) { 19559d81738fSJack F Vogel case e1000_ich8lan: 19569d81738fSJack F Vogel case e1000_ich9lan: 19579d81738fSJack F Vogel case e1000_ich10lan: 19588cfa0ad2SJack F Vogel hw->phy.ops.init_params = e1000_init_phy_params_ich8lan; 19599d81738fSJack F Vogel break; 19609d81738fSJack F Vogel case e1000_pchlan: 19617d9119bdSJack F Vogel case e1000_pch2lan: 19626ab6bfe3SJack F Vogel case e1000_pch_lpt: 1963c80429ceSEric Joyner case e1000_pch_spt: 19646fe4c0a0SSean Bruno case e1000_pch_cnp: 196559690eabSKevin Bowling case e1000_pch_tgp: 196659690eabSKevin Bowling case e1000_pch_adp: 196759690eabSKevin Bowling case e1000_pch_mtp: 19689d81738fSJack F Vogel hw->phy.ops.init_params = e1000_init_phy_params_pchlan; 19699d81738fSJack F Vogel break; 19709d81738fSJack F Vogel default: 19719d81738fSJack F Vogel break; 19729d81738fSJack F Vogel } 19738cfa0ad2SJack F Vogel } 19748cfa0ad2SJack F Vogel 19758cfa0ad2SJack F Vogel /** 19764edd8523SJack F Vogel * e1000_acquire_nvm_ich8lan - Acquire NVM mutex 19774edd8523SJack F Vogel * @hw: pointer to the HW structure 19784edd8523SJack F Vogel * 19794edd8523SJack F Vogel * Acquires the mutex for performing NVM operations. 19804edd8523SJack F Vogel **/ 19814edd8523SJack F Vogel static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw) 19824edd8523SJack F Vogel { 19834edd8523SJack F Vogel DEBUGFUNC("e1000_acquire_nvm_ich8lan"); 19844edd8523SJack F Vogel 1985d5210708SMatt Macy ASSERT_CTX_LOCK_HELD(hw); 19864edd8523SJack F Vogel 19874edd8523SJack F Vogel return E1000_SUCCESS; 19884edd8523SJack F Vogel } 19894edd8523SJack F Vogel 19904edd8523SJack F Vogel /** 19914edd8523SJack F Vogel * e1000_release_nvm_ich8lan - Release NVM mutex 19924edd8523SJack F Vogel * @hw: pointer to the HW structure 19934edd8523SJack F Vogel * 19944edd8523SJack F Vogel * Releases the mutex used while performing NVM operations. 19954edd8523SJack F Vogel **/ 19964edd8523SJack F Vogel static void e1000_release_nvm_ich8lan(struct e1000_hw *hw) 19974edd8523SJack F Vogel { 19984edd8523SJack F Vogel DEBUGFUNC("e1000_release_nvm_ich8lan"); 19994edd8523SJack F Vogel 2000d5210708SMatt Macy ASSERT_CTX_LOCK_HELD(hw); 20014edd8523SJack F Vogel } 20024edd8523SJack F Vogel 20034edd8523SJack F Vogel /** 20048cfa0ad2SJack F Vogel * e1000_acquire_swflag_ich8lan - Acquire software control flag 20058cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 20068cfa0ad2SJack F Vogel * 20074edd8523SJack F Vogel * Acquires the software control flag for performing PHY and select 20084edd8523SJack F Vogel * MAC CSR accesses. 20098cfa0ad2SJack F Vogel **/ 20108cfa0ad2SJack F Vogel static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) 20118cfa0ad2SJack F Vogel { 20128cfa0ad2SJack F Vogel u32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT; 20138cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 20148cfa0ad2SJack F Vogel 20158cfa0ad2SJack F Vogel DEBUGFUNC("e1000_acquire_swflag_ich8lan"); 20168cfa0ad2SJack F Vogel 2017d5210708SMatt Macy ASSERT_CTX_LOCK_HELD(hw); 20184edd8523SJack F Vogel 20198cfa0ad2SJack F Vogel while (timeout) { 20208cfa0ad2SJack F Vogel extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); 20214edd8523SJack F Vogel if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)) 20228cfa0ad2SJack F Vogel break; 20234edd8523SJack F Vogel 20248cfa0ad2SJack F Vogel msec_delay_irq(1); 20258cfa0ad2SJack F Vogel timeout--; 20268cfa0ad2SJack F Vogel } 20278cfa0ad2SJack F Vogel 20288cfa0ad2SJack F Vogel if (!timeout) { 20294dab5c37SJack F Vogel DEBUGOUT("SW has already locked the resource.\n"); 20304edd8523SJack F Vogel ret_val = -E1000_ERR_CONFIG; 20314edd8523SJack F Vogel goto out; 20324edd8523SJack F Vogel } 20334edd8523SJack F Vogel 20344edd8523SJack F Vogel timeout = SW_FLAG_TIMEOUT; 20354edd8523SJack F Vogel 20364edd8523SJack F Vogel extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; 20374edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); 20384edd8523SJack F Vogel 20394edd8523SJack F Vogel while (timeout) { 20404edd8523SJack F Vogel extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); 20414edd8523SJack F Vogel if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) 20424edd8523SJack F Vogel break; 20434edd8523SJack F Vogel 20444edd8523SJack F Vogel msec_delay_irq(1); 20454edd8523SJack F Vogel timeout--; 20464edd8523SJack F Vogel } 20474edd8523SJack F Vogel 20484edd8523SJack F Vogel if (!timeout) { 20494dab5c37SJack F Vogel DEBUGOUT2("Failed to acquire the semaphore, FW or HW has it: FWSM=0x%8.8x EXTCNF_CTRL=0x%8.8x)\n", 20504dab5c37SJack F Vogel E1000_READ_REG(hw, E1000_FWSM), extcnf_ctrl); 20518cfa0ad2SJack F Vogel extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; 20528cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); 20538cfa0ad2SJack F Vogel ret_val = -E1000_ERR_CONFIG; 20548cfa0ad2SJack F Vogel goto out; 20558cfa0ad2SJack F Vogel } 20568cfa0ad2SJack F Vogel 20578cfa0ad2SJack F Vogel out: 20588cfa0ad2SJack F Vogel return ret_val; 20598cfa0ad2SJack F Vogel } 20608cfa0ad2SJack F Vogel 20618cfa0ad2SJack F Vogel /** 20628cfa0ad2SJack F Vogel * e1000_release_swflag_ich8lan - Release software control flag 20638cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 20648cfa0ad2SJack F Vogel * 20654edd8523SJack F Vogel * Releases the software control flag for performing PHY and select 20664edd8523SJack F Vogel * MAC CSR accesses. 20678cfa0ad2SJack F Vogel **/ 20688cfa0ad2SJack F Vogel static void e1000_release_swflag_ich8lan(struct e1000_hw *hw) 20698cfa0ad2SJack F Vogel { 20708cfa0ad2SJack F Vogel u32 extcnf_ctrl; 20718cfa0ad2SJack F Vogel 20728cfa0ad2SJack F Vogel DEBUGFUNC("e1000_release_swflag_ich8lan"); 20738cfa0ad2SJack F Vogel 20748cfa0ad2SJack F Vogel extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); 2075730d3130SJack F Vogel 2076730d3130SJack F Vogel if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) { 20778cfa0ad2SJack F Vogel extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; 20788cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); 2079730d3130SJack F Vogel } else { 2080730d3130SJack F Vogel DEBUGOUT("Semaphore unexpectedly released by sw/fw/hw\n"); 2081730d3130SJack F Vogel } 20828cfa0ad2SJack F Vogel } 20838cfa0ad2SJack F Vogel 20848cfa0ad2SJack F Vogel /** 20858cfa0ad2SJack F Vogel * e1000_check_mng_mode_ich8lan - Checks management mode 20868cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 20878cfa0ad2SJack F Vogel * 20887d9119bdSJack F Vogel * This checks if the adapter has any manageability enabled. 20898cfa0ad2SJack F Vogel * This is a function pointer entry point only called by read/write 20908cfa0ad2SJack F Vogel * routines for the PHY and NVM parts. 20918cfa0ad2SJack F Vogel **/ 20928cfa0ad2SJack F Vogel static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw) 20938cfa0ad2SJack F Vogel { 20948cfa0ad2SJack F Vogel u32 fwsm; 20958cfa0ad2SJack F Vogel 20968cfa0ad2SJack F Vogel DEBUGFUNC("e1000_check_mng_mode_ich8lan"); 20978cfa0ad2SJack F Vogel 20988cfa0ad2SJack F Vogel fwsm = E1000_READ_REG(hw, E1000_FWSM); 20998cfa0ad2SJack F Vogel 21008cc64f1eSJack F Vogel return (fwsm & E1000_ICH_FWSM_FW_VALID) && 21017d9119bdSJack F Vogel ((fwsm & E1000_FWSM_MODE_MASK) == 21028cc64f1eSJack F Vogel (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)); 21037d9119bdSJack F Vogel } 21047d9119bdSJack F Vogel 21057d9119bdSJack F Vogel /** 21067d9119bdSJack F Vogel * e1000_check_mng_mode_pchlan - Checks management mode 21077d9119bdSJack F Vogel * @hw: pointer to the HW structure 21087d9119bdSJack F Vogel * 21097d9119bdSJack F Vogel * This checks if the adapter has iAMT enabled. 21107d9119bdSJack F Vogel * This is a function pointer entry point only called by read/write 21117d9119bdSJack F Vogel * routines for the PHY and NVM parts. 21127d9119bdSJack F Vogel **/ 21137d9119bdSJack F Vogel static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw) 21147d9119bdSJack F Vogel { 21157d9119bdSJack F Vogel u32 fwsm; 21167d9119bdSJack F Vogel 21177d9119bdSJack F Vogel DEBUGFUNC("e1000_check_mng_mode_pchlan"); 21187d9119bdSJack F Vogel 21197d9119bdSJack F Vogel fwsm = E1000_READ_REG(hw, E1000_FWSM); 21207d9119bdSJack F Vogel 21217d9119bdSJack F Vogel return (fwsm & E1000_ICH_FWSM_FW_VALID) && 21227d9119bdSJack F Vogel (fwsm & (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)); 21237d9119bdSJack F Vogel } 21247d9119bdSJack F Vogel 21257d9119bdSJack F Vogel /** 21267d9119bdSJack F Vogel * e1000_rar_set_pch2lan - Set receive address register 21277d9119bdSJack F Vogel * @hw: pointer to the HW structure 21287d9119bdSJack F Vogel * @addr: pointer to the receive address 21297d9119bdSJack F Vogel * @index: receive address array register 21307d9119bdSJack F Vogel * 21317d9119bdSJack F Vogel * Sets the receive address array register at index to the address passed 21327d9119bdSJack F Vogel * in by addr. For 82579, RAR[0] is the base address register that is to 21337d9119bdSJack F Vogel * contain the MAC address but RAR[1-6] are reserved for manageability (ME). 21347d9119bdSJack F Vogel * Use SHRA[0-3] in place of those reserved for ME. 21357d9119bdSJack F Vogel **/ 21368cc64f1eSJack F Vogel static int e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index) 21377d9119bdSJack F Vogel { 21387d9119bdSJack F Vogel u32 rar_low, rar_high; 21397d9119bdSJack F Vogel 21407d9119bdSJack F Vogel DEBUGFUNC("e1000_rar_set_pch2lan"); 21417d9119bdSJack F Vogel 21426ab6bfe3SJack F Vogel /* HW expects these in little endian so we reverse the byte order 21437d9119bdSJack F Vogel * from network order (big endian) to little endian 21447d9119bdSJack F Vogel */ 21457d9119bdSJack F Vogel rar_low = ((u32) addr[0] | 21467d9119bdSJack F Vogel ((u32) addr[1] << 8) | 21477d9119bdSJack F Vogel ((u32) addr[2] << 16) | ((u32) addr[3] << 24)); 21487d9119bdSJack F Vogel 21497d9119bdSJack F Vogel rar_high = ((u32) addr[4] | ((u32) addr[5] << 8)); 21507d9119bdSJack F Vogel 21517d9119bdSJack F Vogel /* If MAC address zero, no need to set the AV bit */ 21527d9119bdSJack F Vogel if (rar_low || rar_high) 21537d9119bdSJack F Vogel rar_high |= E1000_RAH_AV; 21547d9119bdSJack F Vogel 21557d9119bdSJack F Vogel if (index == 0) { 21567d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_RAL(index), rar_low); 21577d9119bdSJack F Vogel E1000_WRITE_FLUSH(hw); 21587d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_RAH(index), rar_high); 21597d9119bdSJack F Vogel E1000_WRITE_FLUSH(hw); 21608cc64f1eSJack F Vogel return E1000_SUCCESS; 21617d9119bdSJack F Vogel } 21627d9119bdSJack F Vogel 21637609433eSJack F Vogel /* RAR[1-6] are owned by manageability. Skip those and program the 21647609433eSJack F Vogel * next address into the SHRA register array. 21657609433eSJack F Vogel */ 21668cc64f1eSJack F Vogel if (index < (u32) (hw->mac.rar_entry_count)) { 21676ab6bfe3SJack F Vogel s32 ret_val; 21686ab6bfe3SJack F Vogel 21696ab6bfe3SJack F Vogel ret_val = e1000_acquire_swflag_ich8lan(hw); 21706ab6bfe3SJack F Vogel if (ret_val) 21716ab6bfe3SJack F Vogel goto out; 21726ab6bfe3SJack F Vogel 21737d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_SHRAL(index - 1), rar_low); 21747d9119bdSJack F Vogel E1000_WRITE_FLUSH(hw); 21757d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_SHRAH(index - 1), rar_high); 21767d9119bdSJack F Vogel E1000_WRITE_FLUSH(hw); 21777d9119bdSJack F Vogel 21786ab6bfe3SJack F Vogel e1000_release_swflag_ich8lan(hw); 21796ab6bfe3SJack F Vogel 21807d9119bdSJack F Vogel /* verify the register updates */ 21817d9119bdSJack F Vogel if ((E1000_READ_REG(hw, E1000_SHRAL(index - 1)) == rar_low) && 21827d9119bdSJack F Vogel (E1000_READ_REG(hw, E1000_SHRAH(index - 1)) == rar_high)) 21838cc64f1eSJack F Vogel return E1000_SUCCESS; 21847d9119bdSJack F Vogel 21857d9119bdSJack F Vogel DEBUGOUT2("SHRA[%d] might be locked by ME - FWSM=0x%8.8x\n", 21867d9119bdSJack F Vogel (index - 1), E1000_READ_REG(hw, E1000_FWSM)); 21877d9119bdSJack F Vogel } 21887d9119bdSJack F Vogel 21896ab6bfe3SJack F Vogel out: 21906ab6bfe3SJack F Vogel DEBUGOUT1("Failed to write receive address at index %d\n", index); 21918cc64f1eSJack F Vogel return -E1000_ERR_CONFIG; 21926ab6bfe3SJack F Vogel } 21936ab6bfe3SJack F Vogel 21946ab6bfe3SJack F Vogel /** 21956ab6bfe3SJack F Vogel * e1000_rar_set_pch_lpt - Set receive address registers 21966ab6bfe3SJack F Vogel * @hw: pointer to the HW structure 21976ab6bfe3SJack F Vogel * @addr: pointer to the receive address 21986ab6bfe3SJack F Vogel * @index: receive address array register 21996ab6bfe3SJack F Vogel * 22006ab6bfe3SJack F Vogel * Sets the receive address register array at index to the address passed 22016ab6bfe3SJack F Vogel * in by addr. For LPT, RAR[0] is the base address register that is to 22026ab6bfe3SJack F Vogel * contain the MAC address. SHRA[0-10] are the shared receive address 22036ab6bfe3SJack F Vogel * registers that are shared between the Host and manageability engine (ME). 22046ab6bfe3SJack F Vogel **/ 22058cc64f1eSJack F Vogel static int e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index) 22066ab6bfe3SJack F Vogel { 22076ab6bfe3SJack F Vogel u32 rar_low, rar_high; 22086ab6bfe3SJack F Vogel u32 wlock_mac; 22096ab6bfe3SJack F Vogel 22106ab6bfe3SJack F Vogel DEBUGFUNC("e1000_rar_set_pch_lpt"); 22116ab6bfe3SJack F Vogel 22126ab6bfe3SJack F Vogel /* HW expects these in little endian so we reverse the byte order 22136ab6bfe3SJack F Vogel * from network order (big endian) to little endian 22146ab6bfe3SJack F Vogel */ 22156ab6bfe3SJack F Vogel rar_low = ((u32) addr[0] | ((u32) addr[1] << 8) | 22166ab6bfe3SJack F Vogel ((u32) addr[2] << 16) | ((u32) addr[3] << 24)); 22176ab6bfe3SJack F Vogel 22186ab6bfe3SJack F Vogel rar_high = ((u32) addr[4] | ((u32) addr[5] << 8)); 22196ab6bfe3SJack F Vogel 22206ab6bfe3SJack F Vogel /* If MAC address zero, no need to set the AV bit */ 22216ab6bfe3SJack F Vogel if (rar_low || rar_high) 22226ab6bfe3SJack F Vogel rar_high |= E1000_RAH_AV; 22236ab6bfe3SJack F Vogel 22246ab6bfe3SJack F Vogel if (index == 0) { 22256ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_RAL(index), rar_low); 22266ab6bfe3SJack F Vogel E1000_WRITE_FLUSH(hw); 22276ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_RAH(index), rar_high); 22286ab6bfe3SJack F Vogel E1000_WRITE_FLUSH(hw); 22298cc64f1eSJack F Vogel return E1000_SUCCESS; 22306ab6bfe3SJack F Vogel } 22316ab6bfe3SJack F Vogel 22326ab6bfe3SJack F Vogel /* The manageability engine (ME) can lock certain SHRAR registers that 22336ab6bfe3SJack F Vogel * it is using - those registers are unavailable for use. 22346ab6bfe3SJack F Vogel */ 22356ab6bfe3SJack F Vogel if (index < hw->mac.rar_entry_count) { 22366ab6bfe3SJack F Vogel wlock_mac = E1000_READ_REG(hw, E1000_FWSM) & 22376ab6bfe3SJack F Vogel E1000_FWSM_WLOCK_MAC_MASK; 22386ab6bfe3SJack F Vogel wlock_mac >>= E1000_FWSM_WLOCK_MAC_SHIFT; 22396ab6bfe3SJack F Vogel 22406ab6bfe3SJack F Vogel /* Check if all SHRAR registers are locked */ 22416ab6bfe3SJack F Vogel if (wlock_mac == 1) 22426ab6bfe3SJack F Vogel goto out; 22436ab6bfe3SJack F Vogel 22446ab6bfe3SJack F Vogel if ((wlock_mac == 0) || (index <= wlock_mac)) { 22456ab6bfe3SJack F Vogel s32 ret_val; 22466ab6bfe3SJack F Vogel 22476ab6bfe3SJack F Vogel ret_val = e1000_acquire_swflag_ich8lan(hw); 22486ab6bfe3SJack F Vogel 22496ab6bfe3SJack F Vogel if (ret_val) 22506ab6bfe3SJack F Vogel goto out; 22516ab6bfe3SJack F Vogel 22526ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_SHRAL_PCH_LPT(index - 1), 22536ab6bfe3SJack F Vogel rar_low); 22546ab6bfe3SJack F Vogel E1000_WRITE_FLUSH(hw); 22556ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_SHRAH_PCH_LPT(index - 1), 22566ab6bfe3SJack F Vogel rar_high); 22576ab6bfe3SJack F Vogel E1000_WRITE_FLUSH(hw); 22586ab6bfe3SJack F Vogel 22596ab6bfe3SJack F Vogel e1000_release_swflag_ich8lan(hw); 22606ab6bfe3SJack F Vogel 22616ab6bfe3SJack F Vogel /* verify the register updates */ 22626ab6bfe3SJack F Vogel if ((E1000_READ_REG(hw, E1000_SHRAL_PCH_LPT(index - 1)) == rar_low) && 22636ab6bfe3SJack F Vogel (E1000_READ_REG(hw, E1000_SHRAH_PCH_LPT(index - 1)) == rar_high)) 22648cc64f1eSJack F Vogel return E1000_SUCCESS; 22656ab6bfe3SJack F Vogel } 22666ab6bfe3SJack F Vogel } 22676ab6bfe3SJack F Vogel 22686ab6bfe3SJack F Vogel out: 22697d9119bdSJack F Vogel DEBUGOUT1("Failed to write receive address at index %d\n", index); 22708cc64f1eSJack F Vogel return -E1000_ERR_CONFIG; 22718cfa0ad2SJack F Vogel } 22728cfa0ad2SJack F Vogel 22738cfa0ad2SJack F Vogel /** 2274730d3130SJack F Vogel * e1000_update_mc_addr_list_pch2lan - Update Multicast addresses 2275730d3130SJack F Vogel * @hw: pointer to the HW structure 2276730d3130SJack F Vogel * @mc_addr_list: array of multicast addresses to program 2277730d3130SJack F Vogel * @mc_addr_count: number of multicast addresses to program 2278730d3130SJack F Vogel * 2279730d3130SJack F Vogel * Updates entire Multicast Table Array of the PCH2 MAC and PHY. 2280730d3130SJack F Vogel * The caller must have a packed mc_addr_list of multicast addresses. 2281730d3130SJack F Vogel **/ 2282730d3130SJack F Vogel static void e1000_update_mc_addr_list_pch2lan(struct e1000_hw *hw, 2283730d3130SJack F Vogel u8 *mc_addr_list, 2284730d3130SJack F Vogel u32 mc_addr_count) 2285730d3130SJack F Vogel { 22864dab5c37SJack F Vogel u16 phy_reg = 0; 2287730d3130SJack F Vogel int i; 22884dab5c37SJack F Vogel s32 ret_val; 2289730d3130SJack F Vogel 2290730d3130SJack F Vogel DEBUGFUNC("e1000_update_mc_addr_list_pch2lan"); 2291730d3130SJack F Vogel 2292730d3130SJack F Vogel e1000_update_mc_addr_list_generic(hw, mc_addr_list, mc_addr_count); 2293730d3130SJack F Vogel 22944dab5c37SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 22954dab5c37SJack F Vogel if (ret_val) 22964dab5c37SJack F Vogel return; 22974dab5c37SJack F Vogel 22984dab5c37SJack F Vogel ret_val = e1000_enable_phy_wakeup_reg_access_bm(hw, &phy_reg); 22994dab5c37SJack F Vogel if (ret_val) 23004dab5c37SJack F Vogel goto release; 23014dab5c37SJack F Vogel 2302730d3130SJack F Vogel for (i = 0; i < hw->mac.mta_reg_count; i++) { 23034dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, BM_MTA(i), 23044dab5c37SJack F Vogel (u16)(hw->mac.mta_shadow[i] & 23054dab5c37SJack F Vogel 0xFFFF)); 23064dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, (BM_MTA(i) + 1), 2307730d3130SJack F Vogel (u16)((hw->mac.mta_shadow[i] >> 16) & 2308730d3130SJack F Vogel 0xFFFF)); 2309730d3130SJack F Vogel } 23104dab5c37SJack F Vogel 23114dab5c37SJack F Vogel e1000_disable_phy_wakeup_reg_access_bm(hw, &phy_reg); 23124dab5c37SJack F Vogel 23134dab5c37SJack F Vogel release: 23144dab5c37SJack F Vogel hw->phy.ops.release(hw); 2315730d3130SJack F Vogel } 2316730d3130SJack F Vogel 2317730d3130SJack F Vogel /** 23188cfa0ad2SJack F Vogel * e1000_check_reset_block_ich8lan - Check if PHY reset is blocked 23198cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 23208cfa0ad2SJack F Vogel * 23218cfa0ad2SJack F Vogel * Checks if firmware is blocking the reset of the PHY. 23228cfa0ad2SJack F Vogel * This is a function pointer entry point only called by 23238cfa0ad2SJack F Vogel * reset routines. 23248cfa0ad2SJack F Vogel **/ 23258cfa0ad2SJack F Vogel static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw) 23268cfa0ad2SJack F Vogel { 23278cfa0ad2SJack F Vogel u32 fwsm; 23287609433eSJack F Vogel bool blocked = FALSE; 23297609433eSJack F Vogel int i = 0; 23308cfa0ad2SJack F Vogel 23318cfa0ad2SJack F Vogel DEBUGFUNC("e1000_check_reset_block_ich8lan"); 23328cfa0ad2SJack F Vogel 23337609433eSJack F Vogel do { 23348cfa0ad2SJack F Vogel fwsm = E1000_READ_REG(hw, E1000_FWSM); 23357609433eSJack F Vogel if (!(fwsm & E1000_ICH_FWSM_RSPCIPHY)) { 23367609433eSJack F Vogel blocked = TRUE; 23377609433eSJack F Vogel msec_delay(10); 23387609433eSJack F Vogel continue; 23397609433eSJack F Vogel } 23407609433eSJack F Vogel blocked = FALSE; 2341c80429ceSEric Joyner } while (blocked && (i++ < 30)); 23427609433eSJack F Vogel return blocked ? E1000_BLK_PHY_RESET : E1000_SUCCESS; 23438cfa0ad2SJack F Vogel } 23448cfa0ad2SJack F Vogel 23458cfa0ad2SJack F Vogel /** 23467d9119bdSJack F Vogel * e1000_write_smbus_addr - Write SMBus address to PHY needed during Sx states 23477d9119bdSJack F Vogel * @hw: pointer to the HW structure 23487d9119bdSJack F Vogel * 23497d9119bdSJack F Vogel * Assumes semaphore already acquired. 23507d9119bdSJack F Vogel * 23517d9119bdSJack F Vogel **/ 23527d9119bdSJack F Vogel static s32 e1000_write_smbus_addr(struct e1000_hw *hw) 23537d9119bdSJack F Vogel { 23547d9119bdSJack F Vogel u16 phy_data; 23557d9119bdSJack F Vogel u32 strap = E1000_READ_REG(hw, E1000_STRAP); 23566ab6bfe3SJack F Vogel u32 freq = (strap & E1000_STRAP_SMT_FREQ_MASK) >> 23576ab6bfe3SJack F Vogel E1000_STRAP_SMT_FREQ_SHIFT; 23586ab6bfe3SJack F Vogel s32 ret_val; 23597d9119bdSJack F Vogel 23607d9119bdSJack F Vogel strap &= E1000_STRAP_SMBUS_ADDRESS_MASK; 23617d9119bdSJack F Vogel 23627d9119bdSJack F Vogel ret_val = e1000_read_phy_reg_hv_locked(hw, HV_SMB_ADDR, &phy_data); 23637d9119bdSJack F Vogel if (ret_val) 23646ab6bfe3SJack F Vogel return ret_val; 23657d9119bdSJack F Vogel 23667d9119bdSJack F Vogel phy_data &= ~HV_SMB_ADDR_MASK; 23677d9119bdSJack F Vogel phy_data |= (strap >> E1000_STRAP_SMBUS_ADDRESS_SHIFT); 23687d9119bdSJack F Vogel phy_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID; 23697d9119bdSJack F Vogel 23706ab6bfe3SJack F Vogel if (hw->phy.type == e1000_phy_i217) { 23716ab6bfe3SJack F Vogel /* Restore SMBus frequency */ 23726ab6bfe3SJack F Vogel if (freq--) { 23736ab6bfe3SJack F Vogel phy_data &= ~HV_SMB_ADDR_FREQ_MASK; 23746ab6bfe3SJack F Vogel phy_data |= (freq & (1 << 0)) << 23756ab6bfe3SJack F Vogel HV_SMB_ADDR_FREQ_LOW_SHIFT; 23766ab6bfe3SJack F Vogel phy_data |= (freq & (1 << 1)) << 23776ab6bfe3SJack F Vogel (HV_SMB_ADDR_FREQ_HIGH_SHIFT - 1); 23786ab6bfe3SJack F Vogel } else { 23796ab6bfe3SJack F Vogel DEBUGOUT("Unsupported SMB frequency in PHY\n"); 23806ab6bfe3SJack F Vogel } 23816ab6bfe3SJack F Vogel } 23826ab6bfe3SJack F Vogel 23836ab6bfe3SJack F Vogel return e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR, phy_data); 23847d9119bdSJack F Vogel } 23857d9119bdSJack F Vogel 23867d9119bdSJack F Vogel /** 23874edd8523SJack F Vogel * e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration 23884edd8523SJack F Vogel * @hw: pointer to the HW structure 23894edd8523SJack F Vogel * 23904edd8523SJack F Vogel * SW should configure the LCD from the NVM extended configuration region 23914edd8523SJack F Vogel * as a workaround for certain parts. 23924edd8523SJack F Vogel **/ 23934edd8523SJack F Vogel static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw) 23944edd8523SJack F Vogel { 23954edd8523SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 23964edd8523SJack F Vogel u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask; 2397a69ed8dfSJack F Vogel s32 ret_val = E1000_SUCCESS; 23984edd8523SJack F Vogel u16 word_addr, reg_data, reg_addr, phy_page = 0; 23994edd8523SJack F Vogel 24007d9119bdSJack F Vogel DEBUGFUNC("e1000_sw_lcd_config_ich8lan"); 24014edd8523SJack F Vogel 24026ab6bfe3SJack F Vogel /* Initialize the PHY from the NVM on ICH platforms. This 24034edd8523SJack F Vogel * is needed due to an issue where the NVM configuration is 24044edd8523SJack F Vogel * not properly autoloaded after power transitions. 24054edd8523SJack F Vogel * Therefore, after each PHY reset, we will load the 24064edd8523SJack F Vogel * configuration data out of the NVM manually. 24074edd8523SJack F Vogel */ 24087d9119bdSJack F Vogel switch (hw->mac.type) { 24097d9119bdSJack F Vogel case e1000_ich8lan: 24107d9119bdSJack F Vogel if (phy->type != e1000_phy_igp_3) 24117d9119bdSJack F Vogel return ret_val; 24127d9119bdSJack F Vogel 24137d9119bdSJack F Vogel if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_AMT) || 24147d9119bdSJack F Vogel (hw->device_id == E1000_DEV_ID_ICH8_IGP_C)) { 24154edd8523SJack F Vogel sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG; 24167d9119bdSJack F Vogel break; 24177d9119bdSJack F Vogel } 24187d9119bdSJack F Vogel /* Fall-thru */ 24197d9119bdSJack F Vogel case e1000_pchlan: 24207d9119bdSJack F Vogel case e1000_pch2lan: 24216ab6bfe3SJack F Vogel case e1000_pch_lpt: 2422c80429ceSEric Joyner case e1000_pch_spt: 24236fe4c0a0SSean Bruno case e1000_pch_cnp: 242459690eabSKevin Bowling case e1000_pch_tgp: 242559690eabSKevin Bowling case e1000_pch_adp: 242659690eabSKevin Bowling case e1000_pch_mtp: 24277d9119bdSJack F Vogel sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; 24287d9119bdSJack F Vogel break; 24297d9119bdSJack F Vogel default: 24307d9119bdSJack F Vogel return ret_val; 24317d9119bdSJack F Vogel } 24327d9119bdSJack F Vogel 24337d9119bdSJack F Vogel ret_val = hw->phy.ops.acquire(hw); 24347d9119bdSJack F Vogel if (ret_val) 24357d9119bdSJack F Vogel return ret_val; 24364edd8523SJack F Vogel 24374edd8523SJack F Vogel data = E1000_READ_REG(hw, E1000_FEXTNVM); 24384edd8523SJack F Vogel if (!(data & sw_cfg_mask)) 24396ab6bfe3SJack F Vogel goto release; 24404edd8523SJack F Vogel 24416ab6bfe3SJack F Vogel /* Make sure HW does not configure LCD from PHY 24424edd8523SJack F Vogel * extended configuration before SW configuration 24434edd8523SJack F Vogel */ 24444edd8523SJack F Vogel data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); 24456ab6bfe3SJack F Vogel if ((hw->mac.type < e1000_pch2lan) && 24466ab6bfe3SJack F Vogel (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)) 24476ab6bfe3SJack F Vogel goto release; 24484edd8523SJack F Vogel 24494edd8523SJack F Vogel cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE); 24504edd8523SJack F Vogel cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK; 24514edd8523SJack F Vogel cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT; 24524edd8523SJack F Vogel if (!cnf_size) 24536ab6bfe3SJack F Vogel goto release; 24544edd8523SJack F Vogel 24554edd8523SJack F Vogel cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK; 24564edd8523SJack F Vogel cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT; 24574edd8523SJack F Vogel 24586ab6bfe3SJack F Vogel if (((hw->mac.type == e1000_pchlan) && 24596ab6bfe3SJack F Vogel !(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)) || 24606ab6bfe3SJack F Vogel (hw->mac.type > e1000_pchlan)) { 24616ab6bfe3SJack F Vogel /* HW configures the SMBus address and LEDs when the 24624edd8523SJack F Vogel * OEM and LCD Write Enable bits are set in the NVM. 24634edd8523SJack F Vogel * When both NVM bits are cleared, SW will configure 24644edd8523SJack F Vogel * them instead. 24654edd8523SJack F Vogel */ 24667d9119bdSJack F Vogel ret_val = e1000_write_smbus_addr(hw); 24674edd8523SJack F Vogel if (ret_val) 24686ab6bfe3SJack F Vogel goto release; 24694edd8523SJack F Vogel 24704edd8523SJack F Vogel data = E1000_READ_REG(hw, E1000_LEDCTL); 2471a69ed8dfSJack F Vogel ret_val = e1000_write_phy_reg_hv_locked(hw, HV_LED_CONFIG, 24724edd8523SJack F Vogel (u16)data); 24734edd8523SJack F Vogel if (ret_val) 24746ab6bfe3SJack F Vogel goto release; 24754edd8523SJack F Vogel } 24764edd8523SJack F Vogel 24774edd8523SJack F Vogel /* Configure LCD from extended configuration region. */ 24784edd8523SJack F Vogel 24794edd8523SJack F Vogel /* cnf_base_addr is in DWORD */ 24804edd8523SJack F Vogel word_addr = (u16)(cnf_base_addr << 1); 24814edd8523SJack F Vogel 24824edd8523SJack F Vogel for (i = 0; i < cnf_size; i++) { 24834edd8523SJack F Vogel ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2), 1, 24844edd8523SJack F Vogel ®_data); 24854edd8523SJack F Vogel if (ret_val) 24866ab6bfe3SJack F Vogel goto release; 24874edd8523SJack F Vogel 24884edd8523SJack F Vogel ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2 + 1), 24894edd8523SJack F Vogel 1, ®_addr); 24904edd8523SJack F Vogel if (ret_val) 24916ab6bfe3SJack F Vogel goto release; 24924edd8523SJack F Vogel 24934edd8523SJack F Vogel /* Save off the PHY page for future writes. */ 24944edd8523SJack F Vogel if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) { 24954edd8523SJack F Vogel phy_page = reg_data; 24964edd8523SJack F Vogel continue; 24974edd8523SJack F Vogel } 24984edd8523SJack F Vogel 24994edd8523SJack F Vogel reg_addr &= PHY_REG_MASK; 25004edd8523SJack F Vogel reg_addr |= phy_page; 25014edd8523SJack F Vogel 25024edd8523SJack F Vogel ret_val = phy->ops.write_reg_locked(hw, (u32)reg_addr, 25034edd8523SJack F Vogel reg_data); 25044edd8523SJack F Vogel if (ret_val) 25056ab6bfe3SJack F Vogel goto release; 25064edd8523SJack F Vogel } 25074edd8523SJack F Vogel 25086ab6bfe3SJack F Vogel release: 25094edd8523SJack F Vogel hw->phy.ops.release(hw); 25104edd8523SJack F Vogel return ret_val; 25114edd8523SJack F Vogel } 25124edd8523SJack F Vogel 25134edd8523SJack F Vogel /** 25144edd8523SJack F Vogel * e1000_k1_gig_workaround_hv - K1 Si workaround 25154edd8523SJack F Vogel * @hw: pointer to the HW structure 25164edd8523SJack F Vogel * @link: link up bool flag 25174edd8523SJack F Vogel * 25184edd8523SJack F Vogel * If K1 is enabled for 1Gbps, the MAC might stall when transitioning 25194edd8523SJack F Vogel * from a lower speed. This workaround disables K1 whenever link is at 1Gig 25204edd8523SJack F Vogel * If link is down, the function will restore the default K1 setting located 25214edd8523SJack F Vogel * in the NVM. 25224edd8523SJack F Vogel **/ 25234edd8523SJack F Vogel static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link) 25244edd8523SJack F Vogel { 25254edd8523SJack F Vogel s32 ret_val = E1000_SUCCESS; 25264edd8523SJack F Vogel u16 status_reg = 0; 25274edd8523SJack F Vogel bool k1_enable = hw->dev_spec.ich8lan.nvm_k1_enabled; 25284edd8523SJack F Vogel 25294edd8523SJack F Vogel DEBUGFUNC("e1000_k1_gig_workaround_hv"); 25304edd8523SJack F Vogel 25314edd8523SJack F Vogel if (hw->mac.type != e1000_pchlan) 25326ab6bfe3SJack F Vogel return E1000_SUCCESS; 25334edd8523SJack F Vogel 25344edd8523SJack F Vogel /* Wrap the whole flow with the sw flag */ 25354edd8523SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 25364edd8523SJack F Vogel if (ret_val) 25376ab6bfe3SJack F Vogel return ret_val; 25384edd8523SJack F Vogel 25394edd8523SJack F Vogel /* Disable K1 when link is 1Gbps, otherwise use the NVM setting */ 25404edd8523SJack F Vogel if (link) { 25414edd8523SJack F Vogel if (hw->phy.type == e1000_phy_82578) { 25424edd8523SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, BM_CS_STATUS, 25434edd8523SJack F Vogel &status_reg); 25444edd8523SJack F Vogel if (ret_val) 25454edd8523SJack F Vogel goto release; 25464edd8523SJack F Vogel 25477609433eSJack F Vogel status_reg &= (BM_CS_STATUS_LINK_UP | 25484edd8523SJack F Vogel BM_CS_STATUS_RESOLVED | 25497609433eSJack F Vogel BM_CS_STATUS_SPEED_MASK); 25504edd8523SJack F Vogel 25514edd8523SJack F Vogel if (status_reg == (BM_CS_STATUS_LINK_UP | 25524edd8523SJack F Vogel BM_CS_STATUS_RESOLVED | 25534edd8523SJack F Vogel BM_CS_STATUS_SPEED_1000)) 25544edd8523SJack F Vogel k1_enable = FALSE; 25554edd8523SJack F Vogel } 25564edd8523SJack F Vogel 25574edd8523SJack F Vogel if (hw->phy.type == e1000_phy_82577) { 25584edd8523SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, HV_M_STATUS, 25594edd8523SJack F Vogel &status_reg); 25604edd8523SJack F Vogel if (ret_val) 25614edd8523SJack F Vogel goto release; 25624edd8523SJack F Vogel 25637609433eSJack F Vogel status_reg &= (HV_M_STATUS_LINK_UP | 25644edd8523SJack F Vogel HV_M_STATUS_AUTONEG_COMPLETE | 25657609433eSJack F Vogel HV_M_STATUS_SPEED_MASK); 25664edd8523SJack F Vogel 25674edd8523SJack F Vogel if (status_reg == (HV_M_STATUS_LINK_UP | 25684edd8523SJack F Vogel HV_M_STATUS_AUTONEG_COMPLETE | 25694edd8523SJack F Vogel HV_M_STATUS_SPEED_1000)) 25704edd8523SJack F Vogel k1_enable = FALSE; 25714edd8523SJack F Vogel } 25724edd8523SJack F Vogel 25734edd8523SJack F Vogel /* Link stall fix for link up */ 25744edd8523SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19), 25754edd8523SJack F Vogel 0x0100); 25764edd8523SJack F Vogel if (ret_val) 25774edd8523SJack F Vogel goto release; 25784edd8523SJack F Vogel 25794edd8523SJack F Vogel } else { 25804edd8523SJack F Vogel /* Link stall fix for link down */ 25814edd8523SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19), 25824edd8523SJack F Vogel 0x4100); 25834edd8523SJack F Vogel if (ret_val) 25844edd8523SJack F Vogel goto release; 25854edd8523SJack F Vogel } 25864edd8523SJack F Vogel 25874edd8523SJack F Vogel ret_val = e1000_configure_k1_ich8lan(hw, k1_enable); 25884edd8523SJack F Vogel 25894edd8523SJack F Vogel release: 25904edd8523SJack F Vogel hw->phy.ops.release(hw); 25916ab6bfe3SJack F Vogel 25924edd8523SJack F Vogel return ret_val; 25934edd8523SJack F Vogel } 25944edd8523SJack F Vogel 25954edd8523SJack F Vogel /** 25964edd8523SJack F Vogel * e1000_configure_k1_ich8lan - Configure K1 power state 25974edd8523SJack F Vogel * @hw: pointer to the HW structure 2598*fc7682b1SKevin Bowling * @k1_enable: K1 state to configure 25994edd8523SJack F Vogel * 26004edd8523SJack F Vogel * Configure the K1 power state based on the provided parameter. 26014edd8523SJack F Vogel * Assumes semaphore already acquired. 26024edd8523SJack F Vogel * 26034edd8523SJack F Vogel * Success returns 0, Failure returns -E1000_ERR_PHY (-2) 26044edd8523SJack F Vogel **/ 26054edd8523SJack F Vogel s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable) 26064edd8523SJack F Vogel { 26076ab6bfe3SJack F Vogel s32 ret_val; 26084edd8523SJack F Vogel u32 ctrl_reg = 0; 26094edd8523SJack F Vogel u32 ctrl_ext = 0; 26104edd8523SJack F Vogel u32 reg = 0; 26114edd8523SJack F Vogel u16 kmrn_reg = 0; 26124edd8523SJack F Vogel 26137d9119bdSJack F Vogel DEBUGFUNC("e1000_configure_k1_ich8lan"); 26147d9119bdSJack F Vogel 26154dab5c37SJack F Vogel ret_val = e1000_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG, 26164edd8523SJack F Vogel &kmrn_reg); 26174edd8523SJack F Vogel if (ret_val) 26186ab6bfe3SJack F Vogel return ret_val; 26194edd8523SJack F Vogel 26204edd8523SJack F Vogel if (k1_enable) 26214edd8523SJack F Vogel kmrn_reg |= E1000_KMRNCTRLSTA_K1_ENABLE; 26224edd8523SJack F Vogel else 26234edd8523SJack F Vogel kmrn_reg &= ~E1000_KMRNCTRLSTA_K1_ENABLE; 26244edd8523SJack F Vogel 26254dab5c37SJack F Vogel ret_val = e1000_write_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG, 26264edd8523SJack F Vogel kmrn_reg); 26274edd8523SJack F Vogel if (ret_val) 26286ab6bfe3SJack F Vogel return ret_val; 26294edd8523SJack F Vogel 26304edd8523SJack F Vogel usec_delay(20); 26314edd8523SJack F Vogel ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); 26324edd8523SJack F Vogel ctrl_reg = E1000_READ_REG(hw, E1000_CTRL); 26334edd8523SJack F Vogel 26344edd8523SJack F Vogel reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); 26354edd8523SJack F Vogel reg |= E1000_CTRL_FRCSPD; 26364edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, reg); 26374edd8523SJack F Vogel 26384edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_SPD_BYPS); 26394dab5c37SJack F Vogel E1000_WRITE_FLUSH(hw); 26404edd8523SJack F Vogel usec_delay(20); 26414edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg); 26424edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); 26434dab5c37SJack F Vogel E1000_WRITE_FLUSH(hw); 26444edd8523SJack F Vogel usec_delay(20); 26454edd8523SJack F Vogel 26466ab6bfe3SJack F Vogel return E1000_SUCCESS; 26474edd8523SJack F Vogel } 26484edd8523SJack F Vogel 26494edd8523SJack F Vogel /** 26504edd8523SJack F Vogel * e1000_oem_bits_config_ich8lan - SW-based LCD Configuration 26514edd8523SJack F Vogel * @hw: pointer to the HW structure 26524edd8523SJack F Vogel * @d0_state: boolean if entering d0 or d3 device state 26534edd8523SJack F Vogel * 26544edd8523SJack F Vogel * SW will configure Gbe Disable and LPLU based on the NVM. The four bits are 26554edd8523SJack F Vogel * collectively called OEM bits. The OEM Write Enable bit and SW Config bit 26564edd8523SJack F Vogel * in NVM determines whether HW should configure LPLU and Gbe Disable. 26574edd8523SJack F Vogel **/ 26584dab5c37SJack F Vogel static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state) 26594edd8523SJack F Vogel { 26604edd8523SJack F Vogel s32 ret_val = 0; 26614edd8523SJack F Vogel u32 mac_reg; 26624edd8523SJack F Vogel u16 oem_reg; 26634edd8523SJack F Vogel 26647d9119bdSJack F Vogel DEBUGFUNC("e1000_oem_bits_config_ich8lan"); 26657d9119bdSJack F Vogel 26666ab6bfe3SJack F Vogel if (hw->mac.type < e1000_pchlan) 26674edd8523SJack F Vogel return ret_val; 26684edd8523SJack F Vogel 26694edd8523SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 26704edd8523SJack F Vogel if (ret_val) 26714edd8523SJack F Vogel return ret_val; 26724edd8523SJack F Vogel 26736ab6bfe3SJack F Vogel if (hw->mac.type == e1000_pchlan) { 26744edd8523SJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); 26754edd8523SJack F Vogel if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) 26766ab6bfe3SJack F Vogel goto release; 26777d9119bdSJack F Vogel } 26784edd8523SJack F Vogel 26794edd8523SJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM); 26804edd8523SJack F Vogel if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M)) 26816ab6bfe3SJack F Vogel goto release; 26824edd8523SJack F Vogel 26834edd8523SJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_PHY_CTRL); 26844edd8523SJack F Vogel 26854edd8523SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, HV_OEM_BITS, &oem_reg); 26864edd8523SJack F Vogel if (ret_val) 26876ab6bfe3SJack F Vogel goto release; 26884edd8523SJack F Vogel 26894edd8523SJack F Vogel oem_reg &= ~(HV_OEM_BITS_GBE_DIS | HV_OEM_BITS_LPLU); 26904edd8523SJack F Vogel 26914edd8523SJack F Vogel if (d0_state) { 26924edd8523SJack F Vogel if (mac_reg & E1000_PHY_CTRL_GBE_DISABLE) 26934edd8523SJack F Vogel oem_reg |= HV_OEM_BITS_GBE_DIS; 26944edd8523SJack F Vogel 26954edd8523SJack F Vogel if (mac_reg & E1000_PHY_CTRL_D0A_LPLU) 26964edd8523SJack F Vogel oem_reg |= HV_OEM_BITS_LPLU; 26974dab5c37SJack F Vogel } else { 26984dab5c37SJack F Vogel if (mac_reg & (E1000_PHY_CTRL_GBE_DISABLE | 26994dab5c37SJack F Vogel E1000_PHY_CTRL_NOND0A_GBE_DISABLE)) 27004dab5c37SJack F Vogel oem_reg |= HV_OEM_BITS_GBE_DIS; 27014dab5c37SJack F Vogel 27024dab5c37SJack F Vogel if (mac_reg & (E1000_PHY_CTRL_D0A_LPLU | 27034dab5c37SJack F Vogel E1000_PHY_CTRL_NOND0A_LPLU)) 27044dab5c37SJack F Vogel oem_reg |= HV_OEM_BITS_LPLU; 27054dab5c37SJack F Vogel } 27064dab5c37SJack F Vogel 27076ab6bfe3SJack F Vogel /* Set Restart auto-neg to activate the bits */ 27086ab6bfe3SJack F Vogel if ((d0_state || (hw->mac.type != e1000_pchlan)) && 27096ab6bfe3SJack F Vogel !hw->phy.ops.check_reset_block(hw)) 27106ab6bfe3SJack F Vogel oem_reg |= HV_OEM_BITS_RESTART_AN; 27116ab6bfe3SJack F Vogel 27124edd8523SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, HV_OEM_BITS, oem_reg); 27134edd8523SJack F Vogel 27146ab6bfe3SJack F Vogel release: 27154edd8523SJack F Vogel hw->phy.ops.release(hw); 27164edd8523SJack F Vogel 27174edd8523SJack F Vogel return ret_val; 27184edd8523SJack F Vogel } 27194edd8523SJack F Vogel 27204edd8523SJack F Vogel 27214edd8523SJack F Vogel /** 2722a69ed8dfSJack F Vogel * e1000_set_mdio_slow_mode_hv - Set slow MDIO access mode 2723a69ed8dfSJack F Vogel * @hw: pointer to the HW structure 2724a69ed8dfSJack F Vogel **/ 2725a69ed8dfSJack F Vogel static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw) 2726a69ed8dfSJack F Vogel { 2727a69ed8dfSJack F Vogel s32 ret_val; 2728a69ed8dfSJack F Vogel u16 data; 2729a69ed8dfSJack F Vogel 27307d9119bdSJack F Vogel DEBUGFUNC("e1000_set_mdio_slow_mode_hv"); 27317d9119bdSJack F Vogel 2732a69ed8dfSJack F Vogel ret_val = hw->phy.ops.read_reg(hw, HV_KMRN_MODE_CTRL, &data); 2733a69ed8dfSJack F Vogel if (ret_val) 2734a69ed8dfSJack F Vogel return ret_val; 2735a69ed8dfSJack F Vogel 2736a69ed8dfSJack F Vogel data |= HV_KMRN_MDIO_SLOW; 2737a69ed8dfSJack F Vogel 2738a69ed8dfSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, HV_KMRN_MODE_CTRL, data); 2739a69ed8dfSJack F Vogel 2740a69ed8dfSJack F Vogel return ret_val; 2741a69ed8dfSJack F Vogel } 2742a69ed8dfSJack F Vogel 2743a69ed8dfSJack F Vogel /** 27449d81738fSJack F Vogel * e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be 27459d81738fSJack F Vogel * done after every PHY reset. 2746*fc7682b1SKevin Bowling * @hw: pointer to the HW structure 27479d81738fSJack F Vogel **/ 27489d81738fSJack F Vogel static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) 27499d81738fSJack F Vogel { 27509d81738fSJack F Vogel s32 ret_val = E1000_SUCCESS; 2751a69ed8dfSJack F Vogel u16 phy_data; 27529d81738fSJack F Vogel 27537d9119bdSJack F Vogel DEBUGFUNC("e1000_hv_phy_workarounds_ich8lan"); 27547d9119bdSJack F Vogel 27559d81738fSJack F Vogel if (hw->mac.type != e1000_pchlan) 27566ab6bfe3SJack F Vogel return E1000_SUCCESS; 27579d81738fSJack F Vogel 2758a69ed8dfSJack F Vogel /* Set MDIO slow mode before any other MDIO access */ 2759a69ed8dfSJack F Vogel if (hw->phy.type == e1000_phy_82577) { 2760a69ed8dfSJack F Vogel ret_val = e1000_set_mdio_slow_mode_hv(hw); 2761a69ed8dfSJack F Vogel if (ret_val) 27626ab6bfe3SJack F Vogel return ret_val; 2763a69ed8dfSJack F Vogel } 2764a69ed8dfSJack F Vogel 27659d81738fSJack F Vogel if (((hw->phy.type == e1000_phy_82577) && 27669d81738fSJack F Vogel ((hw->phy.revision == 1) || (hw->phy.revision == 2))) || 27679d81738fSJack F Vogel ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) { 27689d81738fSJack F Vogel /* Disable generation of early preamble */ 27699d81738fSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431); 27709d81738fSJack F Vogel if (ret_val) 27716ab6bfe3SJack F Vogel return ret_val; 27729d81738fSJack F Vogel 27739d81738fSJack F Vogel /* Preamble tuning for SSC */ 27744dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, HV_KMRN_FIFO_CTRLSTA, 27754dab5c37SJack F Vogel 0xA204); 27769d81738fSJack F Vogel if (ret_val) 27776ab6bfe3SJack F Vogel return ret_val; 27789d81738fSJack F Vogel } 27799d81738fSJack F Vogel 27809d81738fSJack F Vogel if (hw->phy.type == e1000_phy_82578) { 27816ab6bfe3SJack F Vogel /* Return registers to default by doing a soft reset then 27829d81738fSJack F Vogel * writing 0x3140 to the control register. 27839d81738fSJack F Vogel */ 27849d81738fSJack F Vogel if (hw->phy.revision < 2) { 27859d81738fSJack F Vogel e1000_phy_sw_reset_generic(hw); 27869d81738fSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, 27879d81738fSJack F Vogel 0x3140); 27886fe4c0a0SSean Bruno if (ret_val) 27896fe4c0a0SSean Bruno return ret_val; 27909d81738fSJack F Vogel } 27919d81738fSJack F Vogel } 27929d81738fSJack F Vogel 27939d81738fSJack F Vogel /* Select page 0 */ 27949d81738fSJack F Vogel ret_val = hw->phy.ops.acquire(hw); 27959d81738fSJack F Vogel if (ret_val) 27966ab6bfe3SJack F Vogel return ret_val; 27974edd8523SJack F Vogel 27989d81738fSJack F Vogel hw->phy.addr = 1; 27994edd8523SJack F Vogel ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0); 2800a69ed8dfSJack F Vogel hw->phy.ops.release(hw); 28014edd8523SJack F Vogel if (ret_val) 28026ab6bfe3SJack F Vogel return ret_val; 28039d81738fSJack F Vogel 28046ab6bfe3SJack F Vogel /* Configure the K1 Si workaround during phy reset assuming there is 28054edd8523SJack F Vogel * link so that it disables K1 if link is in 1Gbps. 28064edd8523SJack F Vogel */ 28074edd8523SJack F Vogel ret_val = e1000_k1_gig_workaround_hv(hw, TRUE); 2808a69ed8dfSJack F Vogel if (ret_val) 28096ab6bfe3SJack F Vogel return ret_val; 28104edd8523SJack F Vogel 2811a69ed8dfSJack F Vogel /* Workaround for link disconnects on a busy hub in half duplex */ 2812a69ed8dfSJack F Vogel ret_val = hw->phy.ops.acquire(hw); 2813a69ed8dfSJack F Vogel if (ret_val) 28146ab6bfe3SJack F Vogel return ret_val; 28154dab5c37SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, BM_PORT_GEN_CFG, &phy_data); 2816a69ed8dfSJack F Vogel if (ret_val) 2817a69ed8dfSJack F Vogel goto release; 28184dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg_locked(hw, BM_PORT_GEN_CFG, 2819a69ed8dfSJack F Vogel phy_data & 0x00FF); 28206ab6bfe3SJack F Vogel if (ret_val) 28216ab6bfe3SJack F Vogel goto release; 28226ab6bfe3SJack F Vogel 28236ab6bfe3SJack F Vogel /* set MSE higher to enable link to stay up when noise is high */ 28246ab6bfe3SJack F Vogel ret_val = e1000_write_emi_reg_locked(hw, I82577_MSE_THRESHOLD, 0x0034); 2825a69ed8dfSJack F Vogel release: 2826a69ed8dfSJack F Vogel hw->phy.ops.release(hw); 28276ab6bfe3SJack F Vogel 28289d81738fSJack F Vogel return ret_val; 28299d81738fSJack F Vogel } 28309d81738fSJack F Vogel 28319d81738fSJack F Vogel /** 28327d9119bdSJack F Vogel * e1000_copy_rx_addrs_to_phy_ich8lan - Copy Rx addresses from MAC to PHY 28337d9119bdSJack F Vogel * @hw: pointer to the HW structure 28347d9119bdSJack F Vogel **/ 28357d9119bdSJack F Vogel void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw) 28367d9119bdSJack F Vogel { 28377d9119bdSJack F Vogel u32 mac_reg; 28384dab5c37SJack F Vogel u16 i, phy_reg = 0; 28394dab5c37SJack F Vogel s32 ret_val; 28407d9119bdSJack F Vogel 28417d9119bdSJack F Vogel DEBUGFUNC("e1000_copy_rx_addrs_to_phy_ich8lan"); 28427d9119bdSJack F Vogel 28434dab5c37SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 28444dab5c37SJack F Vogel if (ret_val) 28454dab5c37SJack F Vogel return; 28464dab5c37SJack F Vogel ret_val = e1000_enable_phy_wakeup_reg_access_bm(hw, &phy_reg); 28474dab5c37SJack F Vogel if (ret_val) 28484dab5c37SJack F Vogel goto release; 28494dab5c37SJack F Vogel 28507609433eSJack F Vogel /* Copy both RAL/H (rar_entry_count) and SHRAL/H to PHY */ 28517609433eSJack F Vogel for (i = 0; i < (hw->mac.rar_entry_count); i++) { 28527d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_RAL(i)); 28534dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, BM_RAR_L(i), 28544dab5c37SJack F Vogel (u16)(mac_reg & 0xFFFF)); 28554dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, BM_RAR_M(i), 28564dab5c37SJack F Vogel (u16)((mac_reg >> 16) & 0xFFFF)); 28574dab5c37SJack F Vogel 28587d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_RAH(i)); 28594dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, BM_RAR_H(i), 28604dab5c37SJack F Vogel (u16)(mac_reg & 0xFFFF)); 28614dab5c37SJack F Vogel hw->phy.ops.write_reg_page(hw, BM_RAR_CTRL(i), 28624dab5c37SJack F Vogel (u16)((mac_reg & E1000_RAH_AV) 28634dab5c37SJack F Vogel >> 16)); 28647d9119bdSJack F Vogel } 28654dab5c37SJack F Vogel 28664dab5c37SJack F Vogel e1000_disable_phy_wakeup_reg_access_bm(hw, &phy_reg); 28674dab5c37SJack F Vogel 28684dab5c37SJack F Vogel release: 28694dab5c37SJack F Vogel hw->phy.ops.release(hw); 28707d9119bdSJack F Vogel } 28717d9119bdSJack F Vogel 28727d9119bdSJack F Vogel static u32 e1000_calc_rx_da_crc(u8 mac[]) 28737d9119bdSJack F Vogel { 28747d9119bdSJack F Vogel u32 poly = 0xEDB88320; /* Polynomial for 802.3 CRC calculation */ 28757d9119bdSJack F Vogel u32 i, j, mask, crc; 28767d9119bdSJack F Vogel 28777d9119bdSJack F Vogel DEBUGFUNC("e1000_calc_rx_da_crc"); 28787d9119bdSJack F Vogel 28797d9119bdSJack F Vogel crc = 0xffffffff; 28807d9119bdSJack F Vogel for (i = 0; i < 6; i++) { 28817d9119bdSJack F Vogel crc = crc ^ mac[i]; 28827d9119bdSJack F Vogel for (j = 8; j > 0; j--) { 28837d9119bdSJack F Vogel mask = (crc & 1) * (-1); 28847d9119bdSJack F Vogel crc = (crc >> 1) ^ (poly & mask); 28857d9119bdSJack F Vogel } 28867d9119bdSJack F Vogel } 28877d9119bdSJack F Vogel return ~crc; 28887d9119bdSJack F Vogel } 28897d9119bdSJack F Vogel 28907d9119bdSJack F Vogel /** 28917d9119bdSJack F Vogel * e1000_lv_jumbo_workaround_ich8lan - required for jumbo frame operation 28927d9119bdSJack F Vogel * with 82579 PHY 28937d9119bdSJack F Vogel * @hw: pointer to the HW structure 28947d9119bdSJack F Vogel * @enable: flag to enable/disable workaround when enabling/disabling jumbos 28957d9119bdSJack F Vogel **/ 28967d9119bdSJack F Vogel s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable) 28977d9119bdSJack F Vogel { 28987d9119bdSJack F Vogel s32 ret_val = E1000_SUCCESS; 28997d9119bdSJack F Vogel u16 phy_reg, data; 29007d9119bdSJack F Vogel u32 mac_reg; 29017d9119bdSJack F Vogel u16 i; 29027d9119bdSJack F Vogel 29037d9119bdSJack F Vogel DEBUGFUNC("e1000_lv_jumbo_workaround_ich8lan"); 29047d9119bdSJack F Vogel 29056ab6bfe3SJack F Vogel if (hw->mac.type < e1000_pch2lan) 29066ab6bfe3SJack F Vogel return E1000_SUCCESS; 29077d9119bdSJack F Vogel 29087d9119bdSJack F Vogel /* disable Rx path while enabling/disabling workaround */ 29097d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(769, 20), &phy_reg); 29104dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 20), 29114dab5c37SJack F Vogel phy_reg | (1 << 14)); 29127d9119bdSJack F Vogel if (ret_val) 29136ab6bfe3SJack F Vogel return ret_val; 29147d9119bdSJack F Vogel 29157d9119bdSJack F Vogel if (enable) { 29167609433eSJack F Vogel /* Write Rx addresses (rar_entry_count for RAL/H, and 29177d9119bdSJack F Vogel * SHRAL/H) and initial CRC values to the MAC 29187d9119bdSJack F Vogel */ 29197609433eSJack F Vogel for (i = 0; i < hw->mac.rar_entry_count; i++) { 2920e81998f4SEric Joyner u8 mac_addr[ETHER_ADDR_LEN] = {0}; 29217d9119bdSJack F Vogel u32 addr_high, addr_low; 29227d9119bdSJack F Vogel 29237d9119bdSJack F Vogel addr_high = E1000_READ_REG(hw, E1000_RAH(i)); 29247d9119bdSJack F Vogel if (!(addr_high & E1000_RAH_AV)) 29257d9119bdSJack F Vogel continue; 29267d9119bdSJack F Vogel addr_low = E1000_READ_REG(hw, E1000_RAL(i)); 29277d9119bdSJack F Vogel mac_addr[0] = (addr_low & 0xFF); 29287d9119bdSJack F Vogel mac_addr[1] = ((addr_low >> 8) & 0xFF); 29297d9119bdSJack F Vogel mac_addr[2] = ((addr_low >> 16) & 0xFF); 29307d9119bdSJack F Vogel mac_addr[3] = ((addr_low >> 24) & 0xFF); 29317d9119bdSJack F Vogel mac_addr[4] = (addr_high & 0xFF); 29327d9119bdSJack F Vogel mac_addr[5] = ((addr_high >> 8) & 0xFF); 29337d9119bdSJack F Vogel 29347d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_PCH_RAICC(i), 29357d9119bdSJack F Vogel e1000_calc_rx_da_crc(mac_addr)); 29367d9119bdSJack F Vogel } 29377d9119bdSJack F Vogel 29387d9119bdSJack F Vogel /* Write Rx addresses to the PHY */ 29397d9119bdSJack F Vogel e1000_copy_rx_addrs_to_phy_ich8lan(hw); 29407d9119bdSJack F Vogel 29417d9119bdSJack F Vogel /* Enable jumbo frame workaround in the MAC */ 29427d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG); 29437d9119bdSJack F Vogel mac_reg &= ~(1 << 14); 29447d9119bdSJack F Vogel mac_reg |= (7 << 15); 29457d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg); 29467d9119bdSJack F Vogel 29477d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_RCTL); 29487d9119bdSJack F Vogel mac_reg |= E1000_RCTL_SECRC; 29497d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_RCTL, mac_reg); 29507d9119bdSJack F Vogel 29517d9119bdSJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw, 29527d9119bdSJack F Vogel E1000_KMRNCTRLSTA_CTRL_OFFSET, 29537d9119bdSJack F Vogel &data); 29547d9119bdSJack F Vogel if (ret_val) 29556ab6bfe3SJack F Vogel return ret_val; 29567d9119bdSJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 29577d9119bdSJack F Vogel E1000_KMRNCTRLSTA_CTRL_OFFSET, 29587d9119bdSJack F Vogel data | (1 << 0)); 29597d9119bdSJack F Vogel if (ret_val) 29606ab6bfe3SJack F Vogel return ret_val; 29617d9119bdSJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw, 29627d9119bdSJack F Vogel E1000_KMRNCTRLSTA_HD_CTRL, 29637d9119bdSJack F Vogel &data); 29647d9119bdSJack F Vogel if (ret_val) 29656ab6bfe3SJack F Vogel return ret_val; 29667d9119bdSJack F Vogel data &= ~(0xF << 8); 29677d9119bdSJack F Vogel data |= (0xB << 8); 29687d9119bdSJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 29697d9119bdSJack F Vogel E1000_KMRNCTRLSTA_HD_CTRL, 29707d9119bdSJack F Vogel data); 29717d9119bdSJack F Vogel if (ret_val) 29726ab6bfe3SJack F Vogel return ret_val; 29737d9119bdSJack F Vogel 29747d9119bdSJack F Vogel /* Enable jumbo frame workaround in the PHY */ 29757d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data); 29767d9119bdSJack F Vogel data &= ~(0x7F << 5); 29777d9119bdSJack F Vogel data |= (0x37 << 5); 29787d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data); 29797d9119bdSJack F Vogel if (ret_val) 29806ab6bfe3SJack F Vogel return ret_val; 29817d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data); 29827d9119bdSJack F Vogel data &= ~(1 << 13); 29837d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data); 29847d9119bdSJack F Vogel if (ret_val) 29856ab6bfe3SJack F Vogel return ret_val; 29867d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data); 29877d9119bdSJack F Vogel data &= ~(0x3FF << 2); 29888cc64f1eSJack F Vogel data |= (E1000_TX_PTR_GAP << 2); 29897d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data); 29907d9119bdSJack F Vogel if (ret_val) 29916ab6bfe3SJack F Vogel return ret_val; 29924dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0xF100); 29937d9119bdSJack F Vogel if (ret_val) 29946ab6bfe3SJack F Vogel return ret_val; 29957d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data); 29964dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data | 29974dab5c37SJack F Vogel (1 << 10)); 29987d9119bdSJack F Vogel if (ret_val) 29996ab6bfe3SJack F Vogel return ret_val; 30007d9119bdSJack F Vogel } else { 30017d9119bdSJack F Vogel /* Write MAC register values back to h/w defaults */ 30027d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG); 30037d9119bdSJack F Vogel mac_reg &= ~(0xF << 14); 30047d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg); 30057d9119bdSJack F Vogel 30067d9119bdSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_RCTL); 30077d9119bdSJack F Vogel mac_reg &= ~E1000_RCTL_SECRC; 30087d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_RCTL, mac_reg); 30097d9119bdSJack F Vogel 30107d9119bdSJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw, 30117d9119bdSJack F Vogel E1000_KMRNCTRLSTA_CTRL_OFFSET, 30127d9119bdSJack F Vogel &data); 30137d9119bdSJack F Vogel if (ret_val) 30146ab6bfe3SJack F Vogel return ret_val; 30157d9119bdSJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 30167d9119bdSJack F Vogel E1000_KMRNCTRLSTA_CTRL_OFFSET, 30177d9119bdSJack F Vogel data & ~(1 << 0)); 30187d9119bdSJack F Vogel if (ret_val) 30196ab6bfe3SJack F Vogel return ret_val; 30207d9119bdSJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw, 30217d9119bdSJack F Vogel E1000_KMRNCTRLSTA_HD_CTRL, 30227d9119bdSJack F Vogel &data); 30237d9119bdSJack F Vogel if (ret_val) 30246ab6bfe3SJack F Vogel return ret_val; 30257d9119bdSJack F Vogel data &= ~(0xF << 8); 30267d9119bdSJack F Vogel data |= (0xB << 8); 30277d9119bdSJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 30287d9119bdSJack F Vogel E1000_KMRNCTRLSTA_HD_CTRL, 30297d9119bdSJack F Vogel data); 30307d9119bdSJack F Vogel if (ret_val) 30316ab6bfe3SJack F Vogel return ret_val; 30327d9119bdSJack F Vogel 30337d9119bdSJack F Vogel /* Write PHY register values back to h/w defaults */ 30347d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data); 30357d9119bdSJack F Vogel data &= ~(0x7F << 5); 30367d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data); 30377d9119bdSJack F Vogel if (ret_val) 30386ab6bfe3SJack F Vogel return ret_val; 30397d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data); 30407d9119bdSJack F Vogel data |= (1 << 13); 30417d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data); 30427d9119bdSJack F Vogel if (ret_val) 30436ab6bfe3SJack F Vogel return ret_val; 30447d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data); 30457d9119bdSJack F Vogel data &= ~(0x3FF << 2); 30467d9119bdSJack F Vogel data |= (0x8 << 2); 30477d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data); 30487d9119bdSJack F Vogel if (ret_val) 30496ab6bfe3SJack F Vogel return ret_val; 30507d9119bdSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0x7E00); 30517d9119bdSJack F Vogel if (ret_val) 30526ab6bfe3SJack F Vogel return ret_val; 30537d9119bdSJack F Vogel hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data); 30544dab5c37SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data & 30554dab5c37SJack F Vogel ~(1 << 10)); 30567d9119bdSJack F Vogel if (ret_val) 30576ab6bfe3SJack F Vogel return ret_val; 30587d9119bdSJack F Vogel } 30597d9119bdSJack F Vogel 30607d9119bdSJack F Vogel /* re-enable Rx path after enabling/disabling workaround */ 30616ab6bfe3SJack F Vogel return hw->phy.ops.write_reg(hw, PHY_REG(769, 20), phy_reg & 30624dab5c37SJack F Vogel ~(1 << 14)); 30637d9119bdSJack F Vogel } 30647d9119bdSJack F Vogel 30657d9119bdSJack F Vogel /** 30667d9119bdSJack F Vogel * e1000_lv_phy_workarounds_ich8lan - A series of Phy workarounds to be 30677d9119bdSJack F Vogel * done after every PHY reset. 3068*fc7682b1SKevin Bowling * @hw: pointer to the HW structure 30697d9119bdSJack F Vogel **/ 30707d9119bdSJack F Vogel static s32 e1000_lv_phy_workarounds_ich8lan(struct e1000_hw *hw) 30717d9119bdSJack F Vogel { 30727d9119bdSJack F Vogel s32 ret_val = E1000_SUCCESS; 30737d9119bdSJack F Vogel 30747d9119bdSJack F Vogel DEBUGFUNC("e1000_lv_phy_workarounds_ich8lan"); 30757d9119bdSJack F Vogel 30767d9119bdSJack F Vogel if (hw->mac.type != e1000_pch2lan) 30776ab6bfe3SJack F Vogel return E1000_SUCCESS; 30787d9119bdSJack F Vogel 30797d9119bdSJack F Vogel /* Set MDIO slow mode before any other MDIO access */ 30807d9119bdSJack F Vogel ret_val = e1000_set_mdio_slow_mode_hv(hw); 30816ab6bfe3SJack F Vogel if (ret_val) 30826ab6bfe3SJack F Vogel return ret_val; 30837d9119bdSJack F Vogel 30844dab5c37SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 30854dab5c37SJack F Vogel if (ret_val) 30866ab6bfe3SJack F Vogel return ret_val; 30874dab5c37SJack F Vogel /* set MSE higher to enable link to stay up when noise is high */ 30886ab6bfe3SJack F Vogel ret_val = e1000_write_emi_reg_locked(hw, I82579_MSE_THRESHOLD, 0x0034); 30894dab5c37SJack F Vogel if (ret_val) 30904dab5c37SJack F Vogel goto release; 30914dab5c37SJack F Vogel /* drop link after 5 times MSE threshold was reached */ 30926ab6bfe3SJack F Vogel ret_val = e1000_write_emi_reg_locked(hw, I82579_MSE_LINK_DOWN, 0x0005); 30934dab5c37SJack F Vogel release: 30944dab5c37SJack F Vogel hw->phy.ops.release(hw); 30954dab5c37SJack F Vogel 30967d9119bdSJack F Vogel return ret_val; 30977d9119bdSJack F Vogel } 30987d9119bdSJack F Vogel 30997d9119bdSJack F Vogel /** 31007d9119bdSJack F Vogel * e1000_k1_gig_workaround_lv - K1 Si workaround 31017d9119bdSJack F Vogel * @hw: pointer to the HW structure 31027d9119bdSJack F Vogel * 31038cc64f1eSJack F Vogel * Workaround to set the K1 beacon duration for 82579 parts in 10Mbps 31048cc64f1eSJack F Vogel * Disable K1 for 1000 and 100 speeds 31057d9119bdSJack F Vogel **/ 31067d9119bdSJack F Vogel static s32 e1000_k1_workaround_lv(struct e1000_hw *hw) 31077d9119bdSJack F Vogel { 31087d9119bdSJack F Vogel s32 ret_val = E1000_SUCCESS; 31097d9119bdSJack F Vogel u16 status_reg = 0; 31107d9119bdSJack F Vogel 31117d9119bdSJack F Vogel DEBUGFUNC("e1000_k1_workaround_lv"); 31127d9119bdSJack F Vogel 31137d9119bdSJack F Vogel if (hw->mac.type != e1000_pch2lan) 31146ab6bfe3SJack F Vogel return E1000_SUCCESS; 31157d9119bdSJack F Vogel 31168cc64f1eSJack F Vogel /* Set K1 beacon duration based on 10Mbs speed */ 31177d9119bdSJack F Vogel ret_val = hw->phy.ops.read_reg(hw, HV_M_STATUS, &status_reg); 31187d9119bdSJack F Vogel if (ret_val) 31196ab6bfe3SJack F Vogel return ret_val; 31207d9119bdSJack F Vogel 31217d9119bdSJack F Vogel if ((status_reg & (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE)) 31227d9119bdSJack F Vogel == (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE)) { 31238cc64f1eSJack F Vogel if (status_reg & 31248cc64f1eSJack F Vogel (HV_M_STATUS_SPEED_1000 | HV_M_STATUS_SPEED_100)) { 31256ab6bfe3SJack F Vogel u16 pm_phy_reg; 31266ab6bfe3SJack F Vogel 31278cc64f1eSJack F Vogel /* LV 1G/100 Packet drop issue wa */ 31286ab6bfe3SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, HV_PM_CTRL, 31296ab6bfe3SJack F Vogel &pm_phy_reg); 31306ab6bfe3SJack F Vogel if (ret_val) 31316ab6bfe3SJack F Vogel return ret_val; 31328cc64f1eSJack F Vogel pm_phy_reg &= ~HV_PM_CTRL_K1_ENABLE; 31336ab6bfe3SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, 31346ab6bfe3SJack F Vogel pm_phy_reg); 31356ab6bfe3SJack F Vogel if (ret_val) 31366ab6bfe3SJack F Vogel return ret_val; 31374dab5c37SJack F Vogel } else { 31388cc64f1eSJack F Vogel u32 mac_reg; 31398cc64f1eSJack F Vogel mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM4); 31408cc64f1eSJack F Vogel mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK; 31414dab5c37SJack F Vogel mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_16USEC; 31427d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM4, mac_reg); 31438cc64f1eSJack F Vogel } 31447d9119bdSJack F Vogel } 31457d9119bdSJack F Vogel 31467d9119bdSJack F Vogel return ret_val; 31477d9119bdSJack F Vogel } 31487d9119bdSJack F Vogel 31497d9119bdSJack F Vogel /** 31507d9119bdSJack F Vogel * e1000_gate_hw_phy_config_ich8lan - disable PHY config via hardware 31517d9119bdSJack F Vogel * @hw: pointer to the HW structure 3152730d3130SJack F Vogel * @gate: boolean set to TRUE to gate, FALSE to ungate 31537d9119bdSJack F Vogel * 31547d9119bdSJack F Vogel * Gate/ungate the automatic PHY configuration via hardware; perform 31557d9119bdSJack F Vogel * the configuration via software instead. 31567d9119bdSJack F Vogel **/ 31577d9119bdSJack F Vogel static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate) 31587d9119bdSJack F Vogel { 31597d9119bdSJack F Vogel u32 extcnf_ctrl; 31607d9119bdSJack F Vogel 31617d9119bdSJack F Vogel DEBUGFUNC("e1000_gate_hw_phy_config_ich8lan"); 31627d9119bdSJack F Vogel 31636ab6bfe3SJack F Vogel if (hw->mac.type < e1000_pch2lan) 31647d9119bdSJack F Vogel return; 31657d9119bdSJack F Vogel 31667d9119bdSJack F Vogel extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); 31677d9119bdSJack F Vogel 31687d9119bdSJack F Vogel if (gate) 31697d9119bdSJack F Vogel extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG; 31707d9119bdSJack F Vogel else 31717d9119bdSJack F Vogel extcnf_ctrl &= ~E1000_EXTCNF_CTRL_GATE_PHY_CFG; 31727d9119bdSJack F Vogel 31737d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); 31747d9119bdSJack F Vogel } 31757d9119bdSJack F Vogel 31767d9119bdSJack F Vogel /** 31779d81738fSJack F Vogel * e1000_lan_init_done_ich8lan - Check for PHY config completion 31788cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 31798cfa0ad2SJack F Vogel * 31809d81738fSJack F Vogel * Check the appropriate indication the MAC has finished configuring the 31819d81738fSJack F Vogel * PHY after a software reset. 31828cfa0ad2SJack F Vogel **/ 31839d81738fSJack F Vogel static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw) 31848cfa0ad2SJack F Vogel { 31859d81738fSJack F Vogel u32 data, loop = E1000_ICH8_LAN_INIT_TIMEOUT; 31868cfa0ad2SJack F Vogel 31879d81738fSJack F Vogel DEBUGFUNC("e1000_lan_init_done_ich8lan"); 31888cfa0ad2SJack F Vogel 31899d81738fSJack F Vogel /* Wait for basic configuration completes before proceeding */ 31909d81738fSJack F Vogel do { 31919d81738fSJack F Vogel data = E1000_READ_REG(hw, E1000_STATUS); 31929d81738fSJack F Vogel data &= E1000_STATUS_LAN_INIT_DONE; 31939d81738fSJack F Vogel usec_delay(100); 31949d81738fSJack F Vogel } while ((!data) && --loop); 31958cfa0ad2SJack F Vogel 31966ab6bfe3SJack F Vogel /* If basic configuration is incomplete before the above loop 31979d81738fSJack F Vogel * count reaches 0, loading the configuration from NVM will 31989d81738fSJack F Vogel * leave the PHY in a bad state possibly resulting in no link. 31999d81738fSJack F Vogel */ 32009d81738fSJack F Vogel if (loop == 0) 32019d81738fSJack F Vogel DEBUGOUT("LAN_INIT_DONE not set, increase timeout\n"); 32028cfa0ad2SJack F Vogel 32039d81738fSJack F Vogel /* Clear the Init Done bit for the next init event */ 32049d81738fSJack F Vogel data = E1000_READ_REG(hw, E1000_STATUS); 32059d81738fSJack F Vogel data &= ~E1000_STATUS_LAN_INIT_DONE; 32069d81738fSJack F Vogel E1000_WRITE_REG(hw, E1000_STATUS, data); 32078cfa0ad2SJack F Vogel } 32088cfa0ad2SJack F Vogel 32098cfa0ad2SJack F Vogel /** 32107d9119bdSJack F Vogel * e1000_post_phy_reset_ich8lan - Perform steps required after a PHY reset 32117d9119bdSJack F Vogel * @hw: pointer to the HW structure 32127d9119bdSJack F Vogel **/ 32137d9119bdSJack F Vogel static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw) 32147d9119bdSJack F Vogel { 32157d9119bdSJack F Vogel s32 ret_val = E1000_SUCCESS; 32167d9119bdSJack F Vogel u16 reg; 32177d9119bdSJack F Vogel 32187d9119bdSJack F Vogel DEBUGFUNC("e1000_post_phy_reset_ich8lan"); 32197d9119bdSJack F Vogel 32207d9119bdSJack F Vogel if (hw->phy.ops.check_reset_block(hw)) 32216ab6bfe3SJack F Vogel return E1000_SUCCESS; 32227d9119bdSJack F Vogel 32237d9119bdSJack F Vogel /* Allow time for h/w to get to quiescent state after reset */ 32247d9119bdSJack F Vogel msec_delay(10); 32257d9119bdSJack F Vogel 32267d9119bdSJack F Vogel /* Perform any necessary post-reset workarounds */ 32277d9119bdSJack F Vogel switch (hw->mac.type) { 32287d9119bdSJack F Vogel case e1000_pchlan: 32297d9119bdSJack F Vogel ret_val = e1000_hv_phy_workarounds_ich8lan(hw); 32307d9119bdSJack F Vogel if (ret_val) 32316ab6bfe3SJack F Vogel return ret_val; 32327d9119bdSJack F Vogel break; 32337d9119bdSJack F Vogel case e1000_pch2lan: 32347d9119bdSJack F Vogel ret_val = e1000_lv_phy_workarounds_ich8lan(hw); 32357d9119bdSJack F Vogel if (ret_val) 32366ab6bfe3SJack F Vogel return ret_val; 32377d9119bdSJack F Vogel break; 32387d9119bdSJack F Vogel default: 32397d9119bdSJack F Vogel break; 32407d9119bdSJack F Vogel } 32417d9119bdSJack F Vogel 32424dab5c37SJack F Vogel /* Clear the host wakeup bit after lcd reset */ 32434dab5c37SJack F Vogel if (hw->mac.type >= e1000_pchlan) { 32444dab5c37SJack F Vogel hw->phy.ops.read_reg(hw, BM_PORT_GEN_CFG, ®); 32454dab5c37SJack F Vogel reg &= ~BM_WUC_HOST_WU_BIT; 32464dab5c37SJack F Vogel hw->phy.ops.write_reg(hw, BM_PORT_GEN_CFG, reg); 32477d9119bdSJack F Vogel } 32487d9119bdSJack F Vogel 32497d9119bdSJack F Vogel /* Configure the LCD with the extended configuration region in NVM */ 32507d9119bdSJack F Vogel ret_val = e1000_sw_lcd_config_ich8lan(hw); 32517d9119bdSJack F Vogel if (ret_val) 32526ab6bfe3SJack F Vogel return ret_val; 32537d9119bdSJack F Vogel 32547d9119bdSJack F Vogel /* Configure the LCD with the OEM bits in NVM */ 32557d9119bdSJack F Vogel ret_val = e1000_oem_bits_config_ich8lan(hw, TRUE); 32567d9119bdSJack F Vogel 3257730d3130SJack F Vogel if (hw->mac.type == e1000_pch2lan) { 32587d9119bdSJack F Vogel /* Ungate automatic PHY configuration on non-managed 82579 */ 3259730d3130SJack F Vogel if (!(E1000_READ_REG(hw, E1000_FWSM) & 3260730d3130SJack F Vogel E1000_ICH_FWSM_FW_VALID)) { 32617d9119bdSJack F Vogel msec_delay(10); 32627d9119bdSJack F Vogel e1000_gate_hw_phy_config_ich8lan(hw, FALSE); 32637d9119bdSJack F Vogel } 32647d9119bdSJack F Vogel 3265730d3130SJack F Vogel /* Set EEE LPI Update Timer to 200usec */ 3266730d3130SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 3267730d3130SJack F Vogel if (ret_val) 32686ab6bfe3SJack F Vogel return ret_val; 32696ab6bfe3SJack F Vogel ret_val = e1000_write_emi_reg_locked(hw, 32706ab6bfe3SJack F Vogel I82579_LPI_UPDATE_TIMER, 3271730d3130SJack F Vogel 0x1387); 3272730d3130SJack F Vogel hw->phy.ops.release(hw); 3273730d3130SJack F Vogel } 3274730d3130SJack F Vogel 32757d9119bdSJack F Vogel return ret_val; 32767d9119bdSJack F Vogel } 32777d9119bdSJack F Vogel 32787d9119bdSJack F Vogel /** 32798cfa0ad2SJack F Vogel * e1000_phy_hw_reset_ich8lan - Performs a PHY reset 32808cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 32818cfa0ad2SJack F Vogel * 32828cfa0ad2SJack F Vogel * Resets the PHY 32838cfa0ad2SJack F Vogel * This is a function pointer entry point called by drivers 32848cfa0ad2SJack F Vogel * or other shared routines. 32858cfa0ad2SJack F Vogel **/ 32868cfa0ad2SJack F Vogel static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw) 32878cfa0ad2SJack F Vogel { 32884edd8523SJack F Vogel s32 ret_val = E1000_SUCCESS; 32898cfa0ad2SJack F Vogel 32908cfa0ad2SJack F Vogel DEBUGFUNC("e1000_phy_hw_reset_ich8lan"); 32918cfa0ad2SJack F Vogel 32927d9119bdSJack F Vogel /* Gate automatic PHY configuration by hardware on non-managed 82579 */ 32937d9119bdSJack F Vogel if ((hw->mac.type == e1000_pch2lan) && 32947d9119bdSJack F Vogel !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID)) 32957d9119bdSJack F Vogel e1000_gate_hw_phy_config_ich8lan(hw, TRUE); 32967d9119bdSJack F Vogel 32978cfa0ad2SJack F Vogel ret_val = e1000_phy_hw_reset_generic(hw); 32988cfa0ad2SJack F Vogel if (ret_val) 32998cfa0ad2SJack F Vogel return ret_val; 33006ab6bfe3SJack F Vogel 33016ab6bfe3SJack F Vogel return e1000_post_phy_reset_ich8lan(hw); 33028cfa0ad2SJack F Vogel } 33038cfa0ad2SJack F Vogel 33048cfa0ad2SJack F Vogel /** 33054edd8523SJack F Vogel * e1000_set_lplu_state_pchlan - Set Low Power Link Up state 33068cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 33074edd8523SJack F Vogel * @active: TRUE to enable LPLU, FALSE to disable 33088cfa0ad2SJack F Vogel * 33094edd8523SJack F Vogel * Sets the LPLU state according to the active flag. For PCH, if OEM write 33104edd8523SJack F Vogel * bit are disabled in the NVM, writing the LPLU bits in the MAC will not set 33114edd8523SJack F Vogel * the phy speed. This function will manually set the LPLU bit and restart 33124edd8523SJack F Vogel * auto-neg as hw would do. D3 and D0 LPLU will call the same function 33134edd8523SJack F Vogel * since it configures the same bit. 33148cfa0ad2SJack F Vogel **/ 33154edd8523SJack F Vogel static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active) 33168cfa0ad2SJack F Vogel { 33176ab6bfe3SJack F Vogel s32 ret_val; 33184edd8523SJack F Vogel u16 oem_reg; 33198cfa0ad2SJack F Vogel 33204edd8523SJack F Vogel DEBUGFUNC("e1000_set_lplu_state_pchlan"); 33214edd8523SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, HV_OEM_BITS, &oem_reg); 33228cfa0ad2SJack F Vogel if (ret_val) 33236ab6bfe3SJack F Vogel return ret_val; 33248cfa0ad2SJack F Vogel 33254edd8523SJack F Vogel if (active) 33264edd8523SJack F Vogel oem_reg |= HV_OEM_BITS_LPLU; 33274edd8523SJack F Vogel else 33284edd8523SJack F Vogel oem_reg &= ~HV_OEM_BITS_LPLU; 33298cfa0ad2SJack F Vogel 33304dab5c37SJack F Vogel if (!hw->phy.ops.check_reset_block(hw)) 33314edd8523SJack F Vogel oem_reg |= HV_OEM_BITS_RESTART_AN; 33324dab5c37SJack F Vogel 33336ab6bfe3SJack F Vogel return hw->phy.ops.write_reg(hw, HV_OEM_BITS, oem_reg); 33348cfa0ad2SJack F Vogel } 33358cfa0ad2SJack F Vogel 33368cfa0ad2SJack F Vogel /** 33378cfa0ad2SJack F Vogel * e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state 33388cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 33398cfa0ad2SJack F Vogel * @active: TRUE to enable LPLU, FALSE to disable 33408cfa0ad2SJack F Vogel * 33418cfa0ad2SJack F Vogel * Sets the LPLU D0 state according to the active flag. When 33428cfa0ad2SJack F Vogel * activating LPLU this function also disables smart speed 33438cfa0ad2SJack F Vogel * and vice versa. LPLU will not be activated unless the 33448cfa0ad2SJack F Vogel * device autonegotiation advertisement meets standards of 33458cfa0ad2SJack F Vogel * either 10 or 10/100 or 10/100/1000 at all duplexes. 33468cfa0ad2SJack F Vogel * This is a function pointer entry point only called by 33478cfa0ad2SJack F Vogel * PHY setup routines. 33488cfa0ad2SJack F Vogel **/ 3349daf9197cSJack F Vogel static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active) 33508cfa0ad2SJack F Vogel { 33518cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 33528cfa0ad2SJack F Vogel u32 phy_ctrl; 33538cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 33548cfa0ad2SJack F Vogel u16 data; 33558cfa0ad2SJack F Vogel 33568cfa0ad2SJack F Vogel DEBUGFUNC("e1000_set_d0_lplu_state_ich8lan"); 33578cfa0ad2SJack F Vogel 33588cfa0ad2SJack F Vogel if (phy->type == e1000_phy_ife) 33596ab6bfe3SJack F Vogel return E1000_SUCCESS; 33608cfa0ad2SJack F Vogel 33618cfa0ad2SJack F Vogel phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); 33628cfa0ad2SJack F Vogel 33638cfa0ad2SJack F Vogel if (active) { 33648cfa0ad2SJack F Vogel phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU; 33658cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 33668cfa0ad2SJack F Vogel 33679d81738fSJack F Vogel if (phy->type != e1000_phy_igp_3) 33686ab6bfe3SJack F Vogel return E1000_SUCCESS; 33699d81738fSJack F Vogel 33706ab6bfe3SJack F Vogel /* Call gig speed drop workaround on LPLU before accessing 33718cfa0ad2SJack F Vogel * any PHY registers 33728cfa0ad2SJack F Vogel */ 33739d81738fSJack F Vogel if (hw->mac.type == e1000_ich8lan) 33748cfa0ad2SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw); 33758cfa0ad2SJack F Vogel 33768cfa0ad2SJack F Vogel /* When LPLU is enabled, we should disable SmartSpeed */ 33778cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 33788cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 33798cfa0ad2SJack F Vogel &data); 33806ab6bfe3SJack F Vogel if (ret_val) 33816ab6bfe3SJack F Vogel return ret_val; 33828cfa0ad2SJack F Vogel data &= ~IGP01E1000_PSCFR_SMART_SPEED; 33838cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 33848cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 33858cfa0ad2SJack F Vogel data); 33868cfa0ad2SJack F Vogel if (ret_val) 33876ab6bfe3SJack F Vogel return ret_val; 33888cfa0ad2SJack F Vogel } else { 33898cfa0ad2SJack F Vogel phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU; 33908cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 33918cfa0ad2SJack F Vogel 33929d81738fSJack F Vogel if (phy->type != e1000_phy_igp_3) 33936ab6bfe3SJack F Vogel return E1000_SUCCESS; 33949d81738fSJack F Vogel 33956ab6bfe3SJack F Vogel /* LPLU and SmartSpeed are mutually exclusive. LPLU is used 33968cfa0ad2SJack F Vogel * during Dx states where the power conservation is most 33978cfa0ad2SJack F Vogel * important. During driver activity we should enable 33988cfa0ad2SJack F Vogel * SmartSpeed, so performance is maintained. 33998cfa0ad2SJack F Vogel */ 34008cfa0ad2SJack F Vogel if (phy->smart_speed == e1000_smart_speed_on) { 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 if (ret_val) 34126ab6bfe3SJack F Vogel return ret_val; 34138cfa0ad2SJack F Vogel } else if (phy->smart_speed == e1000_smart_speed_off) { 34148cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 34158cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 34168cfa0ad2SJack F Vogel &data); 34178cfa0ad2SJack F Vogel if (ret_val) 34186ab6bfe3SJack F Vogel return ret_val; 34198cfa0ad2SJack F Vogel 34208cfa0ad2SJack F Vogel data &= ~IGP01E1000_PSCFR_SMART_SPEED; 34218cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 34228cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 34238cfa0ad2SJack F Vogel data); 34248cfa0ad2SJack F Vogel if (ret_val) 34256ab6bfe3SJack F Vogel return ret_val; 34268cfa0ad2SJack F Vogel } 34278cfa0ad2SJack F Vogel } 34288cfa0ad2SJack F Vogel 34296ab6bfe3SJack F Vogel return E1000_SUCCESS; 34308cfa0ad2SJack F Vogel } 34318cfa0ad2SJack F Vogel 34328cfa0ad2SJack F Vogel /** 34338cfa0ad2SJack F Vogel * e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state 34348cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 34358cfa0ad2SJack F Vogel * @active: TRUE to enable LPLU, FALSE to disable 34368cfa0ad2SJack F Vogel * 34378cfa0ad2SJack F Vogel * Sets the LPLU D3 state according to the active flag. When 34388cfa0ad2SJack F Vogel * activating LPLU this function also disables smart speed 34398cfa0ad2SJack F Vogel * and vice versa. LPLU will not be activated unless the 34408cfa0ad2SJack F Vogel * device autonegotiation advertisement meets standards of 34418cfa0ad2SJack F Vogel * either 10 or 10/100 or 10/100/1000 at all duplexes. 34428cfa0ad2SJack F Vogel * This is a function pointer entry point only called by 34438cfa0ad2SJack F Vogel * PHY setup routines. 34448cfa0ad2SJack F Vogel **/ 3445daf9197cSJack F Vogel static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active) 34468cfa0ad2SJack F Vogel { 34478cfa0ad2SJack F Vogel struct e1000_phy_info *phy = &hw->phy; 34488cfa0ad2SJack F Vogel u32 phy_ctrl; 34498cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 34508cfa0ad2SJack F Vogel u16 data; 34518cfa0ad2SJack F Vogel 34528cfa0ad2SJack F Vogel DEBUGFUNC("e1000_set_d3_lplu_state_ich8lan"); 34538cfa0ad2SJack F Vogel 34548cfa0ad2SJack F Vogel phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); 34558cfa0ad2SJack F Vogel 34568cfa0ad2SJack F Vogel if (!active) { 34578cfa0ad2SJack F Vogel phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU; 34588cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 34599d81738fSJack F Vogel 34609d81738fSJack F Vogel if (phy->type != e1000_phy_igp_3) 34616ab6bfe3SJack F Vogel return E1000_SUCCESS; 34629d81738fSJack F Vogel 34636ab6bfe3SJack F Vogel /* LPLU and SmartSpeed are mutually exclusive. LPLU is used 34648cfa0ad2SJack F Vogel * during Dx states where the power conservation is most 34658cfa0ad2SJack F Vogel * important. During driver activity we should enable 34668cfa0ad2SJack F Vogel * SmartSpeed, so performance is maintained. 34678cfa0ad2SJack F Vogel */ 34688cfa0ad2SJack F Vogel if (phy->smart_speed == e1000_smart_speed_on) { 34698cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 34708cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 34718cfa0ad2SJack F Vogel &data); 34728cfa0ad2SJack F Vogel if (ret_val) 34736ab6bfe3SJack F Vogel return ret_val; 34748cfa0ad2SJack F Vogel 34758cfa0ad2SJack F Vogel data |= IGP01E1000_PSCFR_SMART_SPEED; 34768cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 34778cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 34788cfa0ad2SJack F Vogel data); 34798cfa0ad2SJack F Vogel if (ret_val) 34806ab6bfe3SJack F Vogel return ret_val; 34818cfa0ad2SJack F Vogel } else if (phy->smart_speed == e1000_smart_speed_off) { 34828cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 34838cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 34848cfa0ad2SJack F Vogel &data); 34858cfa0ad2SJack F Vogel if (ret_val) 34866ab6bfe3SJack F Vogel return ret_val; 34878cfa0ad2SJack F Vogel 34888cfa0ad2SJack F Vogel data &= ~IGP01E1000_PSCFR_SMART_SPEED; 34898cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 34908cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 34918cfa0ad2SJack F Vogel data); 34928cfa0ad2SJack F Vogel if (ret_val) 34936ab6bfe3SJack F Vogel return ret_val; 34948cfa0ad2SJack F Vogel } 34958cfa0ad2SJack F Vogel } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || 34968cfa0ad2SJack F Vogel (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || 34978cfa0ad2SJack F Vogel (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { 34988cfa0ad2SJack F Vogel phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU; 34998cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 35008cfa0ad2SJack F Vogel 35019d81738fSJack F Vogel if (phy->type != e1000_phy_igp_3) 35026ab6bfe3SJack F Vogel return E1000_SUCCESS; 35039d81738fSJack F Vogel 35046ab6bfe3SJack F Vogel /* Call gig speed drop workaround on LPLU before accessing 35058cfa0ad2SJack F Vogel * any PHY registers 35068cfa0ad2SJack F Vogel */ 35079d81738fSJack F Vogel if (hw->mac.type == e1000_ich8lan) 35088cfa0ad2SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw); 35098cfa0ad2SJack F Vogel 35108cfa0ad2SJack F Vogel /* When LPLU is enabled, we should disable SmartSpeed */ 35118cfa0ad2SJack F Vogel ret_val = phy->ops.read_reg(hw, 35128cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 35138cfa0ad2SJack F Vogel &data); 35148cfa0ad2SJack F Vogel if (ret_val) 35156ab6bfe3SJack F Vogel return ret_val; 35168cfa0ad2SJack F Vogel 35178cfa0ad2SJack F Vogel data &= ~IGP01E1000_PSCFR_SMART_SPEED; 35188cfa0ad2SJack F Vogel ret_val = phy->ops.write_reg(hw, 35198cfa0ad2SJack F Vogel IGP01E1000_PHY_PORT_CONFIG, 35208cfa0ad2SJack F Vogel data); 35218cfa0ad2SJack F Vogel } 35228cfa0ad2SJack F Vogel 35238cfa0ad2SJack F Vogel return ret_val; 35248cfa0ad2SJack F Vogel } 35258cfa0ad2SJack F Vogel 35268cfa0ad2SJack F Vogel /** 35278cfa0ad2SJack F Vogel * e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1 35288cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 35298cfa0ad2SJack F Vogel * @bank: pointer to the variable that returns the active bank 35308cfa0ad2SJack F Vogel * 35318cfa0ad2SJack F Vogel * Reads signature byte from the NVM using the flash access registers. 3532d035aa2dSJack F Vogel * Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank. 35338cfa0ad2SJack F Vogel **/ 35348cfa0ad2SJack F Vogel static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank) 35358cfa0ad2SJack F Vogel { 3536d035aa2dSJack F Vogel u32 eecd; 35378cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 35388cfa0ad2SJack F Vogel u32 bank1_offset = nvm->flash_bank_size * sizeof(u16); 35398cfa0ad2SJack F Vogel u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1; 3540c80429ceSEric Joyner u32 nvm_dword = 0; 3541d035aa2dSJack F Vogel u8 sig_byte = 0; 35426ab6bfe3SJack F Vogel s32 ret_val; 35438cfa0ad2SJack F Vogel 35447d9119bdSJack F Vogel DEBUGFUNC("e1000_valid_nvm_bank_detect_ich8lan"); 35457d9119bdSJack F Vogel 3546d035aa2dSJack F Vogel switch (hw->mac.type) { 3547c80429ceSEric Joyner case e1000_pch_spt: 35486fe4c0a0SSean Bruno case e1000_pch_cnp: 354959690eabSKevin Bowling case e1000_pch_tgp: 355059690eabSKevin Bowling case e1000_pch_adp: 355159690eabSKevin Bowling case e1000_pch_mtp: 3552c80429ceSEric Joyner bank1_offset = nvm->flash_bank_size; 3553c80429ceSEric Joyner act_offset = E1000_ICH_NVM_SIG_WORD; 3554c80429ceSEric Joyner 3555c80429ceSEric Joyner /* set bank to 0 in case flash read fails */ 3556c80429ceSEric Joyner *bank = 0; 3557c80429ceSEric Joyner 3558c80429ceSEric Joyner /* Check bank 0 */ 3559c80429ceSEric Joyner ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset, 3560c80429ceSEric Joyner &nvm_dword); 3561c80429ceSEric Joyner if (ret_val) 3562c80429ceSEric Joyner return ret_val; 3563c80429ceSEric Joyner sig_byte = (u8)((nvm_dword & 0xFF00) >> 8); 3564c80429ceSEric Joyner if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == 3565c80429ceSEric Joyner E1000_ICH_NVM_SIG_VALUE) { 3566c80429ceSEric Joyner *bank = 0; 3567c80429ceSEric Joyner return E1000_SUCCESS; 3568c80429ceSEric Joyner } 3569c80429ceSEric Joyner 3570c80429ceSEric Joyner /* Check bank 1 */ 3571c80429ceSEric Joyner ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset + 3572c80429ceSEric Joyner bank1_offset, 3573c80429ceSEric Joyner &nvm_dword); 3574c80429ceSEric Joyner if (ret_val) 3575c80429ceSEric Joyner return ret_val; 3576c80429ceSEric Joyner sig_byte = (u8)((nvm_dword & 0xFF00) >> 8); 3577c80429ceSEric Joyner if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == 3578c80429ceSEric Joyner E1000_ICH_NVM_SIG_VALUE) { 3579c80429ceSEric Joyner *bank = 1; 3580c80429ceSEric Joyner return E1000_SUCCESS; 3581c80429ceSEric Joyner } 3582c80429ceSEric Joyner 3583c80429ceSEric Joyner DEBUGOUT("ERROR: No valid NVM bank present\n"); 3584c80429ceSEric Joyner return -E1000_ERR_NVM; 3585d035aa2dSJack F Vogel case e1000_ich8lan: 3586d035aa2dSJack F Vogel case e1000_ich9lan: 3587d035aa2dSJack F Vogel eecd = E1000_READ_REG(hw, E1000_EECD); 3588d035aa2dSJack F Vogel if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) == 3589d035aa2dSJack F Vogel E1000_EECD_SEC1VAL_VALID_MASK) { 3590d035aa2dSJack F Vogel if (eecd & E1000_EECD_SEC1VAL) 35918cfa0ad2SJack F Vogel *bank = 1; 35928cfa0ad2SJack F Vogel else 35938cfa0ad2SJack F Vogel *bank = 0; 3594d035aa2dSJack F Vogel 35956ab6bfe3SJack F Vogel return E1000_SUCCESS; 3596d035aa2dSJack F Vogel } 35974dab5c37SJack F Vogel DEBUGOUT("Unable to determine valid NVM bank via EEC - reading flash signature\n"); 3598d035aa2dSJack F Vogel /* fall-thru */ 3599d035aa2dSJack F Vogel default: 3600d035aa2dSJack F Vogel /* set bank to 0 in case flash read fails */ 36018cfa0ad2SJack F Vogel *bank = 0; 36028cfa0ad2SJack F Vogel 3603d035aa2dSJack F Vogel /* Check bank 0 */ 3604d035aa2dSJack F Vogel ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset, 3605d035aa2dSJack F Vogel &sig_byte); 3606d035aa2dSJack F Vogel if (ret_val) 36076ab6bfe3SJack F Vogel return ret_val; 3608d035aa2dSJack F Vogel if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == 3609d035aa2dSJack F Vogel E1000_ICH_NVM_SIG_VALUE) { 3610d035aa2dSJack F Vogel *bank = 0; 36116ab6bfe3SJack F Vogel return E1000_SUCCESS; 3612d035aa2dSJack F Vogel } 3613d035aa2dSJack F Vogel 3614d035aa2dSJack F Vogel /* Check bank 1 */ 3615d035aa2dSJack F Vogel ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset + 3616d035aa2dSJack F Vogel bank1_offset, 3617d035aa2dSJack F Vogel &sig_byte); 3618d035aa2dSJack F Vogel if (ret_val) 36196ab6bfe3SJack F Vogel return ret_val; 3620d035aa2dSJack F Vogel if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == 3621d035aa2dSJack F Vogel E1000_ICH_NVM_SIG_VALUE) { 36228cfa0ad2SJack F Vogel *bank = 1; 36236ab6bfe3SJack F Vogel return E1000_SUCCESS; 36248cfa0ad2SJack F Vogel } 36258cfa0ad2SJack F Vogel 3626d035aa2dSJack F Vogel DEBUGOUT("ERROR: No valid NVM bank present\n"); 36276ab6bfe3SJack F Vogel return -E1000_ERR_NVM; 3628d035aa2dSJack F Vogel } 36298cfa0ad2SJack F Vogel } 36308cfa0ad2SJack F Vogel 36318cfa0ad2SJack F Vogel /** 3632c80429ceSEric Joyner * e1000_read_nvm_spt - NVM access for SPT 3633c80429ceSEric Joyner * @hw: pointer to the HW structure 3634c80429ceSEric Joyner * @offset: The offset (in bytes) of the word(s) to read. 3635c80429ceSEric Joyner * @words: Size of data to read in words. 3636c80429ceSEric Joyner * @data: pointer to the word(s) to read at offset. 3637c80429ceSEric Joyner * 3638c80429ceSEric Joyner * Reads a word(s) from the NVM 3639c80429ceSEric Joyner **/ 3640c80429ceSEric Joyner static s32 e1000_read_nvm_spt(struct e1000_hw *hw, u16 offset, u16 words, 3641c80429ceSEric Joyner u16 *data) 3642c80429ceSEric Joyner { 3643c80429ceSEric Joyner struct e1000_nvm_info *nvm = &hw->nvm; 3644c80429ceSEric Joyner struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 3645c80429ceSEric Joyner u32 act_offset; 3646c80429ceSEric Joyner s32 ret_val = E1000_SUCCESS; 3647c80429ceSEric Joyner u32 bank = 0; 3648c80429ceSEric Joyner u32 dword = 0; 3649c80429ceSEric Joyner u16 offset_to_read; 3650c80429ceSEric Joyner u16 i; 3651c80429ceSEric Joyner 3652c80429ceSEric Joyner DEBUGFUNC("e1000_read_nvm_spt"); 3653c80429ceSEric Joyner 3654c80429ceSEric Joyner if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || 3655c80429ceSEric Joyner (words == 0)) { 3656c80429ceSEric Joyner DEBUGOUT("nvm parameter(s) out of bounds\n"); 3657c80429ceSEric Joyner ret_val = -E1000_ERR_NVM; 3658c80429ceSEric Joyner goto out; 3659c80429ceSEric Joyner } 3660c80429ceSEric Joyner 3661c80429ceSEric Joyner nvm->ops.acquire(hw); 3662c80429ceSEric Joyner 3663c80429ceSEric Joyner ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); 3664c80429ceSEric Joyner if (ret_val != E1000_SUCCESS) { 3665c80429ceSEric Joyner DEBUGOUT("Could not detect valid bank, assuming bank 0\n"); 3666c80429ceSEric Joyner bank = 0; 3667c80429ceSEric Joyner } 3668c80429ceSEric Joyner 3669c80429ceSEric Joyner act_offset = (bank) ? nvm->flash_bank_size : 0; 3670c80429ceSEric Joyner act_offset += offset; 3671c80429ceSEric Joyner 3672c80429ceSEric Joyner ret_val = E1000_SUCCESS; 3673c80429ceSEric Joyner 3674c80429ceSEric Joyner for (i = 0; i < words; i += 2) { 3675c80429ceSEric Joyner if (words - i == 1) { 3676c80429ceSEric Joyner if (dev_spec->shadow_ram[offset+i].modified) { 3677c80429ceSEric Joyner data[i] = dev_spec->shadow_ram[offset+i].value; 3678c80429ceSEric Joyner } else { 3679c80429ceSEric Joyner offset_to_read = act_offset + i - 3680c80429ceSEric Joyner ((act_offset + i) % 2); 3681c80429ceSEric Joyner ret_val = 3682c80429ceSEric Joyner e1000_read_flash_dword_ich8lan(hw, 3683c80429ceSEric Joyner offset_to_read, 3684c80429ceSEric Joyner &dword); 3685c80429ceSEric Joyner if (ret_val) 3686c80429ceSEric Joyner break; 3687c80429ceSEric Joyner if ((act_offset + i) % 2 == 0) 3688c80429ceSEric Joyner data[i] = (u16)(dword & 0xFFFF); 3689c80429ceSEric Joyner else 3690c80429ceSEric Joyner data[i] = (u16)((dword >> 16) & 0xFFFF); 3691c80429ceSEric Joyner } 3692c80429ceSEric Joyner } else { 3693c80429ceSEric Joyner offset_to_read = act_offset + i; 3694c80429ceSEric Joyner if (!(dev_spec->shadow_ram[offset+i].modified) || 3695c80429ceSEric Joyner !(dev_spec->shadow_ram[offset+i+1].modified)) { 3696c80429ceSEric Joyner ret_val = 3697c80429ceSEric Joyner e1000_read_flash_dword_ich8lan(hw, 3698c80429ceSEric Joyner offset_to_read, 3699c80429ceSEric Joyner &dword); 3700c80429ceSEric Joyner if (ret_val) 3701c80429ceSEric Joyner break; 3702c80429ceSEric Joyner } 3703c80429ceSEric Joyner if (dev_spec->shadow_ram[offset+i].modified) 3704c80429ceSEric Joyner data[i] = dev_spec->shadow_ram[offset+i].value; 3705c80429ceSEric Joyner else 3706c80429ceSEric Joyner data[i] = (u16) (dword & 0xFFFF); 3707c80429ceSEric Joyner if (dev_spec->shadow_ram[offset+i].modified) 3708c80429ceSEric Joyner data[i+1] = 3709c80429ceSEric Joyner dev_spec->shadow_ram[offset+i+1].value; 3710c80429ceSEric Joyner else 3711c80429ceSEric Joyner data[i+1] = (u16) (dword >> 16 & 0xFFFF); 3712c80429ceSEric Joyner } 3713c80429ceSEric Joyner } 3714c80429ceSEric Joyner 3715c80429ceSEric Joyner nvm->ops.release(hw); 3716c80429ceSEric Joyner 3717c80429ceSEric Joyner out: 3718c80429ceSEric Joyner if (ret_val) 3719c80429ceSEric Joyner DEBUGOUT1("NVM read error: %d\n", ret_val); 3720c80429ceSEric Joyner 3721c80429ceSEric Joyner return ret_val; 3722c80429ceSEric Joyner } 3723c80429ceSEric Joyner 3724c80429ceSEric Joyner /** 37258cfa0ad2SJack F Vogel * e1000_read_nvm_ich8lan - Read word(s) from the NVM 37268cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 37278cfa0ad2SJack F Vogel * @offset: The offset (in bytes) of the word(s) to read. 37288cfa0ad2SJack F Vogel * @words: Size of data to read in words 37298cfa0ad2SJack F Vogel * @data: Pointer to the word(s) to read at offset. 37308cfa0ad2SJack F Vogel * 37318cfa0ad2SJack F Vogel * Reads a word(s) from the NVM using the flash access registers. 37328cfa0ad2SJack F Vogel **/ 37338cfa0ad2SJack F Vogel static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, 37348cfa0ad2SJack F Vogel u16 *data) 37358cfa0ad2SJack F Vogel { 37368cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 3737daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 37388cfa0ad2SJack F Vogel u32 act_offset; 37398cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 37408cfa0ad2SJack F Vogel u32 bank = 0; 37418cfa0ad2SJack F Vogel u16 i, word; 37428cfa0ad2SJack F Vogel 37438cfa0ad2SJack F Vogel DEBUGFUNC("e1000_read_nvm_ich8lan"); 37448cfa0ad2SJack F Vogel 37458cfa0ad2SJack F Vogel if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || 37468cfa0ad2SJack F Vogel (words == 0)) { 37478cfa0ad2SJack F Vogel DEBUGOUT("nvm parameter(s) out of bounds\n"); 37488cfa0ad2SJack F Vogel ret_val = -E1000_ERR_NVM; 37498cfa0ad2SJack F Vogel goto out; 37508cfa0ad2SJack F Vogel } 37518cfa0ad2SJack F Vogel 37524edd8523SJack F Vogel nvm->ops.acquire(hw); 37538cfa0ad2SJack F Vogel 37548cfa0ad2SJack F Vogel ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); 37554edd8523SJack F Vogel if (ret_val != E1000_SUCCESS) { 37564edd8523SJack F Vogel DEBUGOUT("Could not detect valid bank, assuming bank 0\n"); 37574edd8523SJack F Vogel bank = 0; 37584edd8523SJack F Vogel } 37598cfa0ad2SJack F Vogel 37608cfa0ad2SJack F Vogel act_offset = (bank) ? nvm->flash_bank_size : 0; 37618cfa0ad2SJack F Vogel act_offset += offset; 37628cfa0ad2SJack F Vogel 37634edd8523SJack F Vogel ret_val = E1000_SUCCESS; 37648cfa0ad2SJack F Vogel for (i = 0; i < words; i++) { 37654dab5c37SJack F Vogel if (dev_spec->shadow_ram[offset+i].modified) { 37668cfa0ad2SJack F Vogel data[i] = dev_spec->shadow_ram[offset+i].value; 37678cfa0ad2SJack F Vogel } else { 37688cfa0ad2SJack F Vogel ret_val = e1000_read_flash_word_ich8lan(hw, 37698cfa0ad2SJack F Vogel act_offset + i, 37708cfa0ad2SJack F Vogel &word); 37718cfa0ad2SJack F Vogel if (ret_val) 37728cfa0ad2SJack F Vogel break; 37738cfa0ad2SJack F Vogel data[i] = word; 37748cfa0ad2SJack F Vogel } 37758cfa0ad2SJack F Vogel } 37768cfa0ad2SJack F Vogel 37778cfa0ad2SJack F Vogel nvm->ops.release(hw); 37788cfa0ad2SJack F Vogel 37798cfa0ad2SJack F Vogel out: 3780d035aa2dSJack F Vogel if (ret_val) 3781d035aa2dSJack F Vogel DEBUGOUT1("NVM read error: %d\n", ret_val); 3782d035aa2dSJack F Vogel 37838cfa0ad2SJack F Vogel return ret_val; 37848cfa0ad2SJack F Vogel } 37858cfa0ad2SJack F Vogel 37868cfa0ad2SJack F Vogel /** 37878cfa0ad2SJack F Vogel * e1000_flash_cycle_init_ich8lan - Initialize flash 37888cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 37898cfa0ad2SJack F Vogel * 37908cfa0ad2SJack F Vogel * This function does initial flash setup so that a new read/write/erase cycle 37918cfa0ad2SJack F Vogel * can be started. 37928cfa0ad2SJack F Vogel **/ 37938cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw) 37948cfa0ad2SJack F Vogel { 37958cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts; 37968cfa0ad2SJack F Vogel s32 ret_val = -E1000_ERR_NVM; 37978cfa0ad2SJack F Vogel 37988cfa0ad2SJack F Vogel DEBUGFUNC("e1000_flash_cycle_init_ich8lan"); 37998cfa0ad2SJack F Vogel 38008cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); 38018cfa0ad2SJack F Vogel 38028cfa0ad2SJack F Vogel /* Check if the flash descriptor is valid */ 38036ab6bfe3SJack F Vogel if (!hsfsts.hsf_status.fldesvalid) { 38044dab5c37SJack F Vogel DEBUGOUT("Flash descriptor invalid. SW Sequencing must be used.\n"); 38056ab6bfe3SJack F Vogel return -E1000_ERR_NVM; 38068cfa0ad2SJack F Vogel } 38078cfa0ad2SJack F Vogel 38088cfa0ad2SJack F Vogel /* Clear FCERR and DAEL in hw status by writing 1 */ 38098cfa0ad2SJack F Vogel hsfsts.hsf_status.flcerr = 1; 38108cfa0ad2SJack F Vogel hsfsts.hsf_status.dael = 1; 3811295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt) 3812c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, 3813c80429ceSEric Joyner hsfsts.regval & 0xFFFF); 3814c80429ceSEric Joyner else 38158cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval); 38168cfa0ad2SJack F Vogel 38176ab6bfe3SJack F Vogel /* Either we should have a hardware SPI cycle in progress 38188cfa0ad2SJack F Vogel * bit to check against, in order to start a new cycle or 38198cfa0ad2SJack F Vogel * FDONE bit should be changed in the hardware so that it 38208cfa0ad2SJack F Vogel * is 1 after hardware reset, which can then be used as an 38218cfa0ad2SJack F Vogel * indication whether a cycle is in progress or has been 38228cfa0ad2SJack F Vogel * completed. 38238cfa0ad2SJack F Vogel */ 38248cfa0ad2SJack F Vogel 38256ab6bfe3SJack F Vogel if (!hsfsts.hsf_status.flcinprog) { 38266ab6bfe3SJack F Vogel /* There is no cycle running at present, 38278cfa0ad2SJack F Vogel * so we can start a cycle. 38288cfa0ad2SJack F Vogel * Begin by setting Flash Cycle Done. 38298cfa0ad2SJack F Vogel */ 38308cfa0ad2SJack F Vogel hsfsts.hsf_status.flcdone = 1; 3831295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt) 3832c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, 3833c80429ceSEric Joyner hsfsts.regval & 0xFFFF); 3834c80429ceSEric Joyner else 3835c80429ceSEric Joyner E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, 3836c80429ceSEric Joyner hsfsts.regval); 38378cfa0ad2SJack F Vogel ret_val = E1000_SUCCESS; 38388cfa0ad2SJack F Vogel } else { 3839730d3130SJack F Vogel s32 i; 3840730d3130SJack F Vogel 38416ab6bfe3SJack F Vogel /* Otherwise poll for sometime so the current 38428cfa0ad2SJack F Vogel * cycle has a chance to end before giving up. 38438cfa0ad2SJack F Vogel */ 38448cfa0ad2SJack F Vogel for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) { 38458cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, 38468cfa0ad2SJack F Vogel ICH_FLASH_HSFSTS); 38476ab6bfe3SJack F Vogel if (!hsfsts.hsf_status.flcinprog) { 38488cfa0ad2SJack F Vogel ret_val = E1000_SUCCESS; 38498cfa0ad2SJack F Vogel break; 38508cfa0ad2SJack F Vogel } 38518cfa0ad2SJack F Vogel usec_delay(1); 38528cfa0ad2SJack F Vogel } 38538cfa0ad2SJack F Vogel if (ret_val == E1000_SUCCESS) { 38546ab6bfe3SJack F Vogel /* Successful in waiting for previous cycle to timeout, 38558cfa0ad2SJack F Vogel * now set the Flash Cycle Done. 38568cfa0ad2SJack F Vogel */ 38578cfa0ad2SJack F Vogel hsfsts.hsf_status.flcdone = 1; 3858295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt) 3859c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, 3860c80429ceSEric Joyner hsfsts.regval & 0xFFFF); 3861c80429ceSEric Joyner else 3862daf9197cSJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, 38638cfa0ad2SJack F Vogel hsfsts.regval); 38648cfa0ad2SJack F Vogel } else { 38654dab5c37SJack F Vogel DEBUGOUT("Flash controller busy, cannot get access\n"); 38668cfa0ad2SJack F Vogel } 38678cfa0ad2SJack F Vogel } 38688cfa0ad2SJack F Vogel 38698cfa0ad2SJack F Vogel return ret_val; 38708cfa0ad2SJack F Vogel } 38718cfa0ad2SJack F Vogel 38728cfa0ad2SJack F Vogel /** 38738cfa0ad2SJack F Vogel * e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase) 38748cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 38758cfa0ad2SJack F Vogel * @timeout: maximum time to wait for completion 38768cfa0ad2SJack F Vogel * 38778cfa0ad2SJack F Vogel * This function starts a flash cycle and waits for its completion. 38788cfa0ad2SJack F Vogel **/ 38798cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout) 38808cfa0ad2SJack F Vogel { 38818cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl hsflctl; 38828cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts; 38838cfa0ad2SJack F Vogel u32 i = 0; 38848cfa0ad2SJack F Vogel 38858cfa0ad2SJack F Vogel DEBUGFUNC("e1000_flash_cycle_ich8lan"); 38868cfa0ad2SJack F Vogel 38878cfa0ad2SJack F Vogel /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */ 3888295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt) 3889c80429ceSEric Joyner hsflctl.regval = E1000_READ_FLASH_REG(hw, ICH_FLASH_HSFSTS)>>16; 3890c80429ceSEric Joyner else 38918cfa0ad2SJack F Vogel hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL); 38928cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.flcgo = 1; 38938cc64f1eSJack F Vogel 3894295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt) 3895c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, 3896c80429ceSEric Joyner hsflctl.regval << 16); 3897c80429ceSEric Joyner else 38988cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval); 38998cfa0ad2SJack F Vogel 39008cfa0ad2SJack F Vogel /* wait till FDONE bit is set to 1 */ 39018cfa0ad2SJack F Vogel do { 39028cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); 39036ab6bfe3SJack F Vogel if (hsfsts.hsf_status.flcdone) 39048cfa0ad2SJack F Vogel break; 39058cfa0ad2SJack F Vogel usec_delay(1); 39068cfa0ad2SJack F Vogel } while (i++ < timeout); 39078cfa0ad2SJack F Vogel 39086ab6bfe3SJack F Vogel if (hsfsts.hsf_status.flcdone && !hsfsts.hsf_status.flcerr) 39096ab6bfe3SJack F Vogel return E1000_SUCCESS; 39108cfa0ad2SJack F Vogel 39116ab6bfe3SJack F Vogel return -E1000_ERR_NVM; 39128cfa0ad2SJack F Vogel } 39138cfa0ad2SJack F Vogel 39148cfa0ad2SJack F Vogel /** 3915c80429ceSEric Joyner * e1000_read_flash_dword_ich8lan - Read dword from flash 3916c80429ceSEric Joyner * @hw: pointer to the HW structure 3917c80429ceSEric Joyner * @offset: offset to data location 3918c80429ceSEric Joyner * @data: pointer to the location for storing the data 3919c80429ceSEric Joyner * 3920c80429ceSEric Joyner * Reads the flash dword at offset into data. Offset is converted 3921c80429ceSEric Joyner * to bytes before read. 3922c80429ceSEric Joyner **/ 3923c80429ceSEric Joyner static s32 e1000_read_flash_dword_ich8lan(struct e1000_hw *hw, u32 offset, 3924c80429ceSEric Joyner u32 *data) 3925c80429ceSEric Joyner { 3926c80429ceSEric Joyner DEBUGFUNC("e1000_read_flash_dword_ich8lan"); 3927c80429ceSEric Joyner 3928c80429ceSEric Joyner if (!data) 3929c80429ceSEric Joyner return -E1000_ERR_NVM; 3930c80429ceSEric Joyner 3931c80429ceSEric Joyner /* Must convert word offset into bytes. */ 3932c80429ceSEric Joyner offset <<= 1; 3933c80429ceSEric Joyner 3934c80429ceSEric Joyner return e1000_read_flash_data32_ich8lan(hw, offset, data); 3935c80429ceSEric Joyner } 3936c80429ceSEric Joyner 3937c80429ceSEric Joyner /** 39388cfa0ad2SJack F Vogel * e1000_read_flash_word_ich8lan - Read word from flash 39398cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 39408cfa0ad2SJack F Vogel * @offset: offset to data location 39418cfa0ad2SJack F Vogel * @data: pointer to the location for storing the data 39428cfa0ad2SJack F Vogel * 39438cfa0ad2SJack F Vogel * Reads the flash word at offset into data. Offset is converted 39448cfa0ad2SJack F Vogel * to bytes before read. 39458cfa0ad2SJack F Vogel **/ 39468cfa0ad2SJack F Vogel static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset, 39478cfa0ad2SJack F Vogel u16 *data) 39488cfa0ad2SJack F Vogel { 39498cfa0ad2SJack F Vogel DEBUGFUNC("e1000_read_flash_word_ich8lan"); 39508cfa0ad2SJack F Vogel 39516ab6bfe3SJack F Vogel if (!data) 39526ab6bfe3SJack F Vogel return -E1000_ERR_NVM; 39538cfa0ad2SJack F Vogel 39548cfa0ad2SJack F Vogel /* Must convert offset into bytes. */ 39558cfa0ad2SJack F Vogel offset <<= 1; 39568cfa0ad2SJack F Vogel 39576ab6bfe3SJack F Vogel return e1000_read_flash_data_ich8lan(hw, offset, 2, data); 39588cfa0ad2SJack F Vogel } 39598cfa0ad2SJack F Vogel 39608cfa0ad2SJack F Vogel /** 39618cfa0ad2SJack F Vogel * e1000_read_flash_byte_ich8lan - Read byte from flash 39628cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 39638cfa0ad2SJack F Vogel * @offset: The offset of the byte to read. 39648cfa0ad2SJack F Vogel * @data: Pointer to a byte to store the value read. 39658cfa0ad2SJack F Vogel * 39668cfa0ad2SJack F Vogel * Reads a single byte from the NVM using the flash access registers. 39678cfa0ad2SJack F Vogel **/ 39688cfa0ad2SJack F Vogel static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, 39698cfa0ad2SJack F Vogel u8 *data) 39708cfa0ad2SJack F Vogel { 39716ab6bfe3SJack F Vogel s32 ret_val; 39728cfa0ad2SJack F Vogel u16 word = 0; 39738cfa0ad2SJack F Vogel 3974c80429ceSEric Joyner /* In SPT, only 32 bits access is supported, 3975c80429ceSEric Joyner * so this function should not be called. 3976c80429ceSEric Joyner */ 3977295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt) 3978c80429ceSEric Joyner return -E1000_ERR_NVM; 3979c80429ceSEric Joyner else 39808cfa0ad2SJack F Vogel ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word); 39818cc64f1eSJack F Vogel 39828cfa0ad2SJack F Vogel if (ret_val) 39836ab6bfe3SJack F Vogel return ret_val; 39848cfa0ad2SJack F Vogel 39858cfa0ad2SJack F Vogel *data = (u8)word; 39868cfa0ad2SJack F Vogel 39876ab6bfe3SJack F Vogel return E1000_SUCCESS; 39888cfa0ad2SJack F Vogel } 39898cfa0ad2SJack F Vogel 39908cfa0ad2SJack F Vogel /** 39918cfa0ad2SJack F Vogel * e1000_read_flash_data_ich8lan - Read byte or word from NVM 39928cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 39938cfa0ad2SJack F Vogel * @offset: The offset (in bytes) of the byte or word to read. 39948cfa0ad2SJack F Vogel * @size: Size of data to read, 1=byte 2=word 39958cfa0ad2SJack F Vogel * @data: Pointer to the word to store the value read. 39968cfa0ad2SJack F Vogel * 39978cfa0ad2SJack F Vogel * Reads a byte or word from the NVM using the flash access registers. 39988cfa0ad2SJack F Vogel **/ 39998cfa0ad2SJack F Vogel static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, 40008cfa0ad2SJack F Vogel u8 size, u16 *data) 40018cfa0ad2SJack F Vogel { 40028cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts; 40038cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl hsflctl; 40048cfa0ad2SJack F Vogel u32 flash_linear_addr; 40058cfa0ad2SJack F Vogel u32 flash_data = 0; 40068cfa0ad2SJack F Vogel s32 ret_val = -E1000_ERR_NVM; 40078cfa0ad2SJack F Vogel u8 count = 0; 40088cfa0ad2SJack F Vogel 40098cfa0ad2SJack F Vogel DEBUGFUNC("e1000_read_flash_data_ich8lan"); 40108cfa0ad2SJack F Vogel 40118cfa0ad2SJack F Vogel if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK) 40126ab6bfe3SJack F Vogel return -E1000_ERR_NVM; 40137609433eSJack F Vogel flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) + 40147609433eSJack F Vogel hw->nvm.flash_base_addr); 40158cfa0ad2SJack F Vogel 40168cfa0ad2SJack F Vogel do { 40178cfa0ad2SJack F Vogel usec_delay(1); 40188cfa0ad2SJack F Vogel /* Steps */ 40198cfa0ad2SJack F Vogel ret_val = e1000_flash_cycle_init_ich8lan(hw); 40208cfa0ad2SJack F Vogel if (ret_val != E1000_SUCCESS) 40218cfa0ad2SJack F Vogel break; 40228cfa0ad2SJack F Vogel hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL); 40238cc64f1eSJack F Vogel 40248cfa0ad2SJack F Vogel /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ 40258cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.fldbcount = size - 1; 40268cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ; 40278cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval); 40288cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr); 40298cfa0ad2SJack F Vogel 40308cc64f1eSJack F Vogel ret_val = e1000_flash_cycle_ich8lan(hw, 40318cfa0ad2SJack F Vogel ICH_FLASH_READ_COMMAND_TIMEOUT); 40328cfa0ad2SJack F Vogel 40336ab6bfe3SJack F Vogel /* Check if FCERR is set to 1, if set to 1, clear it 40348cfa0ad2SJack F Vogel * and try the whole sequence a few more times, else 40358cfa0ad2SJack F Vogel * read in (shift in) the Flash Data0, the order is 40368cfa0ad2SJack F Vogel * least significant byte first msb to lsb 40378cfa0ad2SJack F Vogel */ 40388cfa0ad2SJack F Vogel if (ret_val == E1000_SUCCESS) { 40398cfa0ad2SJack F Vogel flash_data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0); 4040daf9197cSJack F Vogel if (size == 1) 40418cfa0ad2SJack F Vogel *data = (u8)(flash_data & 0x000000FF); 4042daf9197cSJack F Vogel else if (size == 2) 40438cfa0ad2SJack F Vogel *data = (u16)(flash_data & 0x0000FFFF); 40448cfa0ad2SJack F Vogel break; 40458cfa0ad2SJack F Vogel } else { 40466ab6bfe3SJack F Vogel /* If we've gotten here, then things are probably 40478cfa0ad2SJack F Vogel * completely hosed, but if the error condition is 40488cfa0ad2SJack F Vogel * detected, it won't hurt to give it another try... 40498cfa0ad2SJack F Vogel * ICH_FLASH_CYCLE_REPEAT_COUNT times. 40508cfa0ad2SJack F Vogel */ 40518cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, 40528cfa0ad2SJack F Vogel ICH_FLASH_HSFSTS); 40536ab6bfe3SJack F Vogel if (hsfsts.hsf_status.flcerr) { 40548cfa0ad2SJack F Vogel /* Repeat for some time before giving up. */ 40558cfa0ad2SJack F Vogel continue; 40566ab6bfe3SJack F Vogel } else if (!hsfsts.hsf_status.flcdone) { 40574dab5c37SJack F Vogel DEBUGOUT("Timeout error - flash cycle did not complete.\n"); 40588cfa0ad2SJack F Vogel break; 40598cfa0ad2SJack F Vogel } 40608cfa0ad2SJack F Vogel } 40618cfa0ad2SJack F Vogel } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); 40628cfa0ad2SJack F Vogel 40638cfa0ad2SJack F Vogel return ret_val; 40648cfa0ad2SJack F Vogel } 40658cfa0ad2SJack F Vogel 4066c80429ceSEric Joyner /** 4067c80429ceSEric Joyner * e1000_read_flash_data32_ich8lan - Read dword from NVM 4068c80429ceSEric Joyner * @hw: pointer to the HW structure 4069c80429ceSEric Joyner * @offset: The offset (in bytes) of the dword to read. 4070c80429ceSEric Joyner * @data: Pointer to the dword to store the value read. 4071c80429ceSEric Joyner * 4072c80429ceSEric Joyner * Reads a byte or word from the NVM using the flash access registers. 4073c80429ceSEric Joyner **/ 4074c80429ceSEric Joyner static s32 e1000_read_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset, 4075c80429ceSEric Joyner u32 *data) 4076c80429ceSEric Joyner { 4077c80429ceSEric Joyner union ich8_hws_flash_status hsfsts; 4078c80429ceSEric Joyner union ich8_hws_flash_ctrl hsflctl; 4079c80429ceSEric Joyner u32 flash_linear_addr; 4080c80429ceSEric Joyner s32 ret_val = -E1000_ERR_NVM; 4081c80429ceSEric Joyner u8 count = 0; 4082c80429ceSEric Joyner 4083c80429ceSEric Joyner DEBUGFUNC("e1000_read_flash_data_ich8lan"); 4084c80429ceSEric Joyner 4085c80429ceSEric Joyner if (offset > ICH_FLASH_LINEAR_ADDR_MASK || 4086295df609SEric Joyner hw->mac.type < e1000_pch_spt) 4087c80429ceSEric Joyner return -E1000_ERR_NVM; 4088c80429ceSEric Joyner flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) + 4089c80429ceSEric Joyner hw->nvm.flash_base_addr); 4090c80429ceSEric Joyner 4091c80429ceSEric Joyner do { 4092c80429ceSEric Joyner usec_delay(1); 4093c80429ceSEric Joyner /* Steps */ 4094c80429ceSEric Joyner ret_val = e1000_flash_cycle_init_ich8lan(hw); 4095c80429ceSEric Joyner if (ret_val != E1000_SUCCESS) 4096c80429ceSEric Joyner break; 4097c80429ceSEric Joyner /* In SPT, This register is in Lan memory space, not flash. 4098c80429ceSEric Joyner * Therefore, only 32 bit access is supported 4099c80429ceSEric Joyner */ 4100c80429ceSEric Joyner hsflctl.regval = E1000_READ_FLASH_REG(hw, ICH_FLASH_HSFSTS)>>16; 4101c80429ceSEric Joyner 4102c80429ceSEric Joyner /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ 4103c80429ceSEric Joyner hsflctl.hsf_ctrl.fldbcount = sizeof(u32) - 1; 4104c80429ceSEric Joyner hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ; 4105c80429ceSEric Joyner /* In SPT, This register is in Lan memory space, not flash. 4106c80429ceSEric Joyner * Therefore, only 32 bit access is supported 4107c80429ceSEric Joyner */ 4108c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, 4109c80429ceSEric Joyner (u32)hsflctl.regval << 16); 4110c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr); 4111c80429ceSEric Joyner 4112c80429ceSEric Joyner ret_val = e1000_flash_cycle_ich8lan(hw, 4113c80429ceSEric Joyner ICH_FLASH_READ_COMMAND_TIMEOUT); 4114c80429ceSEric Joyner 4115c80429ceSEric Joyner /* Check if FCERR is set to 1, if set to 1, clear it 4116c80429ceSEric Joyner * and try the whole sequence a few more times, else 4117c80429ceSEric Joyner * read in (shift in) the Flash Data0, the order is 4118c80429ceSEric Joyner * least significant byte first msb to lsb 4119c80429ceSEric Joyner */ 4120c80429ceSEric Joyner if (ret_val == E1000_SUCCESS) { 4121c80429ceSEric Joyner *data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0); 4122c80429ceSEric Joyner break; 4123c80429ceSEric Joyner } else { 4124c80429ceSEric Joyner /* If we've gotten here, then things are probably 4125c80429ceSEric Joyner * completely hosed, but if the error condition is 4126c80429ceSEric Joyner * detected, it won't hurt to give it another try... 4127c80429ceSEric Joyner * ICH_FLASH_CYCLE_REPEAT_COUNT times. 4128c80429ceSEric Joyner */ 4129c80429ceSEric Joyner hsfsts.regval = E1000_READ_FLASH_REG16(hw, 4130c80429ceSEric Joyner ICH_FLASH_HSFSTS); 4131c80429ceSEric Joyner if (hsfsts.hsf_status.flcerr) { 4132c80429ceSEric Joyner /* Repeat for some time before giving up. */ 4133c80429ceSEric Joyner continue; 4134c80429ceSEric Joyner } else if (!hsfsts.hsf_status.flcdone) { 4135c80429ceSEric Joyner DEBUGOUT("Timeout error - flash cycle did not complete.\n"); 4136c80429ceSEric Joyner break; 4137c80429ceSEric Joyner } 4138c80429ceSEric Joyner } 4139c80429ceSEric Joyner } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); 4140c80429ceSEric Joyner 4141c80429ceSEric Joyner return ret_val; 4142c80429ceSEric Joyner } 41438cc64f1eSJack F Vogel 41448cfa0ad2SJack F Vogel /** 41458cfa0ad2SJack F Vogel * e1000_write_nvm_ich8lan - Write word(s) to the NVM 41468cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 41478cfa0ad2SJack F Vogel * @offset: The offset (in bytes) of the word(s) to write. 41488cfa0ad2SJack F Vogel * @words: Size of data to write in words 41498cfa0ad2SJack F Vogel * @data: Pointer to the word(s) to write at offset. 41508cfa0ad2SJack F Vogel * 41518cfa0ad2SJack F Vogel * Writes a byte or word to the NVM using the flash access registers. 41528cfa0ad2SJack F Vogel **/ 41538cfa0ad2SJack F Vogel static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, 41548cfa0ad2SJack F Vogel u16 *data) 41558cfa0ad2SJack F Vogel { 41568cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 4157daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 41588cfa0ad2SJack F Vogel u16 i; 41598cfa0ad2SJack F Vogel 41608cfa0ad2SJack F Vogel DEBUGFUNC("e1000_write_nvm_ich8lan"); 41618cfa0ad2SJack F Vogel 41628cfa0ad2SJack F Vogel if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || 41638cfa0ad2SJack F Vogel (words == 0)) { 41648cfa0ad2SJack F Vogel DEBUGOUT("nvm parameter(s) out of bounds\n"); 41656ab6bfe3SJack F Vogel return -E1000_ERR_NVM; 41668cfa0ad2SJack F Vogel } 41678cfa0ad2SJack F Vogel 41684edd8523SJack F Vogel nvm->ops.acquire(hw); 41698cfa0ad2SJack F Vogel 41708cfa0ad2SJack F Vogel for (i = 0; i < words; i++) { 41718cfa0ad2SJack F Vogel dev_spec->shadow_ram[offset+i].modified = TRUE; 41728cfa0ad2SJack F Vogel dev_spec->shadow_ram[offset+i].value = data[i]; 41738cfa0ad2SJack F Vogel } 41748cfa0ad2SJack F Vogel 41758cfa0ad2SJack F Vogel nvm->ops.release(hw); 41768cfa0ad2SJack F Vogel 41776ab6bfe3SJack F Vogel return E1000_SUCCESS; 41788cfa0ad2SJack F Vogel } 41798cfa0ad2SJack F Vogel 41808cfa0ad2SJack F Vogel /** 4181c80429ceSEric Joyner * e1000_update_nvm_checksum_spt - Update the checksum for NVM 4182c80429ceSEric Joyner * @hw: pointer to the HW structure 4183c80429ceSEric Joyner * 4184c80429ceSEric Joyner * The NVM checksum is updated by calling the generic update_nvm_checksum, 4185c80429ceSEric Joyner * which writes the checksum to the shadow ram. The changes in the shadow 4186c80429ceSEric Joyner * ram are then committed to the EEPROM by processing each bank at a time 4187c80429ceSEric Joyner * checking for the modified bit and writing only the pending changes. 4188c80429ceSEric Joyner * After a successful commit, the shadow ram is cleared and is ready for 4189c80429ceSEric Joyner * future writes. 4190c80429ceSEric Joyner **/ 4191c80429ceSEric Joyner static s32 e1000_update_nvm_checksum_spt(struct e1000_hw *hw) 4192c80429ceSEric Joyner { 4193c80429ceSEric Joyner struct e1000_nvm_info *nvm = &hw->nvm; 4194c80429ceSEric Joyner struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 4195c80429ceSEric Joyner u32 i, act_offset, new_bank_offset, old_bank_offset, bank; 4196c80429ceSEric Joyner s32 ret_val; 4197c80429ceSEric Joyner u32 dword = 0; 4198c80429ceSEric Joyner 4199c80429ceSEric Joyner DEBUGFUNC("e1000_update_nvm_checksum_spt"); 4200c80429ceSEric Joyner 4201c80429ceSEric Joyner ret_val = e1000_update_nvm_checksum_generic(hw); 4202c80429ceSEric Joyner if (ret_val) 4203c80429ceSEric Joyner goto out; 4204c80429ceSEric Joyner 4205c80429ceSEric Joyner if (nvm->type != e1000_nvm_flash_sw) 4206c80429ceSEric Joyner goto out; 4207c80429ceSEric Joyner 4208c80429ceSEric Joyner nvm->ops.acquire(hw); 4209c80429ceSEric Joyner 4210c80429ceSEric Joyner /* We're writing to the opposite bank so if we're on bank 1, 4211c80429ceSEric Joyner * write to bank 0 etc. We also need to erase the segment that 4212c80429ceSEric Joyner * is going to be written 4213c80429ceSEric Joyner */ 4214c80429ceSEric Joyner ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); 4215c80429ceSEric Joyner if (ret_val != E1000_SUCCESS) { 4216c80429ceSEric Joyner DEBUGOUT("Could not detect valid bank, assuming bank 0\n"); 4217c80429ceSEric Joyner bank = 0; 4218c80429ceSEric Joyner } 4219c80429ceSEric Joyner 4220c80429ceSEric Joyner if (bank == 0) { 4221c80429ceSEric Joyner new_bank_offset = nvm->flash_bank_size; 4222c80429ceSEric Joyner old_bank_offset = 0; 4223c80429ceSEric Joyner ret_val = e1000_erase_flash_bank_ich8lan(hw, 1); 4224c80429ceSEric Joyner if (ret_val) 4225c80429ceSEric Joyner goto release; 4226c80429ceSEric Joyner } else { 4227c80429ceSEric Joyner old_bank_offset = nvm->flash_bank_size; 4228c80429ceSEric Joyner new_bank_offset = 0; 4229c80429ceSEric Joyner ret_val = e1000_erase_flash_bank_ich8lan(hw, 0); 4230c80429ceSEric Joyner if (ret_val) 4231c80429ceSEric Joyner goto release; 4232c80429ceSEric Joyner } 4233c80429ceSEric Joyner for (i = 0; i < E1000_SHADOW_RAM_WORDS; i += 2) { 4234c80429ceSEric Joyner /* Determine whether to write the value stored 4235c80429ceSEric Joyner * in the other NVM bank or a modified value stored 4236c80429ceSEric Joyner * in the shadow RAM 4237c80429ceSEric Joyner */ 4238c80429ceSEric Joyner ret_val = e1000_read_flash_dword_ich8lan(hw, 4239c80429ceSEric Joyner i + old_bank_offset, 4240c80429ceSEric Joyner &dword); 4241c80429ceSEric Joyner 4242c80429ceSEric Joyner if (dev_spec->shadow_ram[i].modified) { 4243c80429ceSEric Joyner dword &= 0xffff0000; 4244c80429ceSEric Joyner dword |= (dev_spec->shadow_ram[i].value & 0xffff); 4245c80429ceSEric Joyner } 4246c80429ceSEric Joyner if (dev_spec->shadow_ram[i + 1].modified) { 4247c80429ceSEric Joyner dword &= 0x0000ffff; 4248c80429ceSEric Joyner dword |= ((dev_spec->shadow_ram[i + 1].value & 0xffff) 4249c80429ceSEric Joyner << 16); 4250c80429ceSEric Joyner } 4251c80429ceSEric Joyner if (ret_val) 4252c80429ceSEric Joyner break; 4253c80429ceSEric Joyner 4254c80429ceSEric Joyner /* If the word is 0x13, then make sure the signature bits 4255c80429ceSEric Joyner * (15:14) are 11b until the commit has completed. 4256c80429ceSEric Joyner * This will allow us to write 10b which indicates the 4257c80429ceSEric Joyner * signature is valid. We want to do this after the write 4258c80429ceSEric Joyner * has completed so that we don't mark the segment valid 4259c80429ceSEric Joyner * while the write is still in progress 4260c80429ceSEric Joyner */ 4261c80429ceSEric Joyner if (i == E1000_ICH_NVM_SIG_WORD - 1) 4262c80429ceSEric Joyner dword |= E1000_ICH_NVM_SIG_MASK << 16; 4263c80429ceSEric Joyner 4264c80429ceSEric Joyner /* Convert offset to bytes. */ 4265c80429ceSEric Joyner act_offset = (i + new_bank_offset) << 1; 4266c80429ceSEric Joyner 4267c80429ceSEric Joyner usec_delay(100); 4268c80429ceSEric Joyner 4269c80429ceSEric Joyner /* Write the data to the new bank. Offset in words*/ 4270c80429ceSEric Joyner act_offset = i + new_bank_offset; 4271c80429ceSEric Joyner ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset, 4272c80429ceSEric Joyner dword); 4273c80429ceSEric Joyner if (ret_val) 4274c80429ceSEric Joyner break; 4275c80429ceSEric Joyner } 4276c80429ceSEric Joyner 4277c80429ceSEric Joyner /* Don't bother writing the segment valid bits if sector 4278c80429ceSEric Joyner * programming failed. 4279c80429ceSEric Joyner */ 4280c80429ceSEric Joyner if (ret_val) { 4281c80429ceSEric Joyner DEBUGOUT("Flash commit failed.\n"); 4282c80429ceSEric Joyner goto release; 4283c80429ceSEric Joyner } 4284c80429ceSEric Joyner 4285c80429ceSEric Joyner /* Finally validate the new segment by setting bit 15:14 4286c80429ceSEric Joyner * to 10b in word 0x13 , this can be done without an 4287c80429ceSEric Joyner * erase as well since these bits are 11 to start with 4288c80429ceSEric Joyner * and we need to change bit 14 to 0b 4289c80429ceSEric Joyner */ 4290c80429ceSEric Joyner act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD; 4291c80429ceSEric Joyner 4292c80429ceSEric Joyner /*offset in words but we read dword*/ 4293c80429ceSEric Joyner --act_offset; 4294c80429ceSEric Joyner ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset, &dword); 4295c80429ceSEric Joyner 4296c80429ceSEric Joyner if (ret_val) 4297c80429ceSEric Joyner goto release; 4298c80429ceSEric Joyner 4299c80429ceSEric Joyner dword &= 0xBFFFFFFF; 4300c80429ceSEric Joyner ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset, dword); 4301c80429ceSEric Joyner 4302c80429ceSEric Joyner if (ret_val) 4303c80429ceSEric Joyner goto release; 4304c80429ceSEric Joyner 4305c80429ceSEric Joyner /* offset in words but we read dword*/ 4306c80429ceSEric Joyner act_offset = old_bank_offset + E1000_ICH_NVM_SIG_WORD - 1; 4307c80429ceSEric Joyner ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset, &dword); 4308c80429ceSEric Joyner 4309c80429ceSEric Joyner if (ret_val) 4310c80429ceSEric Joyner goto release; 4311c80429ceSEric Joyner 4312c80429ceSEric Joyner dword &= 0x00FFFFFF; 4313c80429ceSEric Joyner ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset, dword); 4314c80429ceSEric Joyner 4315c80429ceSEric Joyner if (ret_val) 4316c80429ceSEric Joyner goto release; 4317c80429ceSEric Joyner 4318c80429ceSEric Joyner /* Great! Everything worked, we can now clear the cached entries. */ 4319c80429ceSEric Joyner for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) { 4320c80429ceSEric Joyner dev_spec->shadow_ram[i].modified = FALSE; 4321c80429ceSEric Joyner dev_spec->shadow_ram[i].value = 0xFFFF; 4322c80429ceSEric Joyner } 4323c80429ceSEric Joyner 4324c80429ceSEric Joyner release: 4325c80429ceSEric Joyner nvm->ops.release(hw); 4326c80429ceSEric Joyner 4327c80429ceSEric Joyner /* Reload the EEPROM, or else modifications will not appear 4328c80429ceSEric Joyner * until after the next adapter reset. 4329c80429ceSEric Joyner */ 4330c80429ceSEric Joyner if (!ret_val) { 4331c80429ceSEric Joyner nvm->ops.reload(hw); 4332c80429ceSEric Joyner msec_delay(10); 4333c80429ceSEric Joyner } 4334c80429ceSEric Joyner 4335c80429ceSEric Joyner out: 4336c80429ceSEric Joyner if (ret_val) 4337c80429ceSEric Joyner DEBUGOUT1("NVM update error: %d\n", ret_val); 4338c80429ceSEric Joyner 4339c80429ceSEric Joyner return ret_val; 4340c80429ceSEric Joyner } 4341c80429ceSEric Joyner 4342c80429ceSEric Joyner /** 43438cfa0ad2SJack F Vogel * e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM 43448cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 43458cfa0ad2SJack F Vogel * 43468cfa0ad2SJack F Vogel * The NVM checksum is updated by calling the generic update_nvm_checksum, 43478cfa0ad2SJack F Vogel * which writes the checksum to the shadow ram. The changes in the shadow 43488cfa0ad2SJack F Vogel * ram are then committed to the EEPROM by processing each bank at a time 43498cfa0ad2SJack F Vogel * checking for the modified bit and writing only the pending changes. 43508cfa0ad2SJack F Vogel * After a successful commit, the shadow ram is cleared and is ready for 43518cfa0ad2SJack F Vogel * future writes. 43528cfa0ad2SJack F Vogel **/ 43538cfa0ad2SJack F Vogel static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) 43548cfa0ad2SJack F Vogel { 43558cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 4356daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 43578cfa0ad2SJack F Vogel u32 i, act_offset, new_bank_offset, old_bank_offset, bank; 43588cfa0ad2SJack F Vogel s32 ret_val; 43598cc64f1eSJack F Vogel u16 data = 0; 43608cfa0ad2SJack F Vogel 43618cfa0ad2SJack F Vogel DEBUGFUNC("e1000_update_nvm_checksum_ich8lan"); 43628cfa0ad2SJack F Vogel 43638cfa0ad2SJack F Vogel ret_val = e1000_update_nvm_checksum_generic(hw); 43648cfa0ad2SJack F Vogel if (ret_val) 43658cfa0ad2SJack F Vogel goto out; 43668cfa0ad2SJack F Vogel 43678cfa0ad2SJack F Vogel if (nvm->type != e1000_nvm_flash_sw) 43688cfa0ad2SJack F Vogel goto out; 43698cfa0ad2SJack F Vogel 43704edd8523SJack F Vogel nvm->ops.acquire(hw); 43718cfa0ad2SJack F Vogel 43726ab6bfe3SJack F Vogel /* We're writing to the opposite bank so if we're on bank 1, 43738cfa0ad2SJack F Vogel * write to bank 0 etc. We also need to erase the segment that 43748cfa0ad2SJack F Vogel * is going to be written 43758cfa0ad2SJack F Vogel */ 43768cfa0ad2SJack F Vogel ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); 4377d035aa2dSJack F Vogel if (ret_val != E1000_SUCCESS) { 43784edd8523SJack F Vogel DEBUGOUT("Could not detect valid bank, assuming bank 0\n"); 43794edd8523SJack F Vogel bank = 0; 4380d035aa2dSJack F Vogel } 43818cfa0ad2SJack F Vogel 43828cfa0ad2SJack F Vogel if (bank == 0) { 43838cfa0ad2SJack F Vogel new_bank_offset = nvm->flash_bank_size; 43848cfa0ad2SJack F Vogel old_bank_offset = 0; 4385d035aa2dSJack F Vogel ret_val = e1000_erase_flash_bank_ich8lan(hw, 1); 4386a69ed8dfSJack F Vogel if (ret_val) 4387a69ed8dfSJack F Vogel goto release; 43888cfa0ad2SJack F Vogel } else { 43898cfa0ad2SJack F Vogel old_bank_offset = nvm->flash_bank_size; 43908cfa0ad2SJack F Vogel new_bank_offset = 0; 4391d035aa2dSJack F Vogel ret_val = e1000_erase_flash_bank_ich8lan(hw, 0); 4392a69ed8dfSJack F Vogel if (ret_val) 4393a69ed8dfSJack F Vogel goto release; 43948cfa0ad2SJack F Vogel } 43958cfa0ad2SJack F Vogel for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) { 43968cfa0ad2SJack F Vogel if (dev_spec->shadow_ram[i].modified) { 43978cfa0ad2SJack F Vogel data = dev_spec->shadow_ram[i].value; 43988cfa0ad2SJack F Vogel } else { 4399d035aa2dSJack F Vogel ret_val = e1000_read_flash_word_ich8lan(hw, i + 4400d035aa2dSJack F Vogel old_bank_offset, 44018cfa0ad2SJack F Vogel &data); 4402d035aa2dSJack F Vogel if (ret_val) 4403d035aa2dSJack F Vogel break; 44048cfa0ad2SJack F Vogel } 44056ab6bfe3SJack F Vogel /* If the word is 0x13, then make sure the signature bits 44068cfa0ad2SJack F Vogel * (15:14) are 11b until the commit has completed. 44078cfa0ad2SJack F Vogel * This will allow us to write 10b which indicates the 44088cfa0ad2SJack F Vogel * signature is valid. We want to do this after the write 44098cfa0ad2SJack F Vogel * has completed so that we don't mark the segment valid 44108cfa0ad2SJack F Vogel * while the write is still in progress 44118cfa0ad2SJack F Vogel */ 44128cfa0ad2SJack F Vogel if (i == E1000_ICH_NVM_SIG_WORD) 44138cfa0ad2SJack F Vogel data |= E1000_ICH_NVM_SIG_MASK; 44148cfa0ad2SJack F Vogel 44158cfa0ad2SJack F Vogel /* Convert offset to bytes. */ 44168cfa0ad2SJack F Vogel act_offset = (i + new_bank_offset) << 1; 44178cfa0ad2SJack F Vogel 44188cfa0ad2SJack F Vogel usec_delay(100); 44198cc64f1eSJack F Vogel 44208cfa0ad2SJack F Vogel /* Write the bytes to the new bank. */ 44218cfa0ad2SJack F Vogel ret_val = e1000_retry_write_flash_byte_ich8lan(hw, 44228cfa0ad2SJack F Vogel act_offset, 44238cfa0ad2SJack F Vogel (u8)data); 44248cfa0ad2SJack F Vogel if (ret_val) 44258cfa0ad2SJack F Vogel break; 44268cfa0ad2SJack F Vogel 44278cfa0ad2SJack F Vogel usec_delay(100); 44288cfa0ad2SJack F Vogel ret_val = e1000_retry_write_flash_byte_ich8lan(hw, 44298cfa0ad2SJack F Vogel act_offset + 1, 44308cfa0ad2SJack F Vogel (u8)(data >> 8)); 44318cfa0ad2SJack F Vogel if (ret_val) 44328cfa0ad2SJack F Vogel break; 44338cfa0ad2SJack F Vogel } 44348cfa0ad2SJack F Vogel 44356ab6bfe3SJack F Vogel /* Don't bother writing the segment valid bits if sector 44368cfa0ad2SJack F Vogel * programming failed. 44378cfa0ad2SJack F Vogel */ 44388cfa0ad2SJack F Vogel if (ret_val) { 44398cfa0ad2SJack F Vogel DEBUGOUT("Flash commit failed.\n"); 4440a69ed8dfSJack F Vogel goto release; 44418cfa0ad2SJack F Vogel } 44428cfa0ad2SJack F Vogel 44436ab6bfe3SJack F Vogel /* Finally validate the new segment by setting bit 15:14 44448cfa0ad2SJack F Vogel * to 10b in word 0x13 , this can be done without an 44458cfa0ad2SJack F Vogel * erase as well since these bits are 11 to start with 44468cfa0ad2SJack F Vogel * and we need to change bit 14 to 0b 44478cfa0ad2SJack F Vogel */ 44488cfa0ad2SJack F Vogel act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD; 4449d035aa2dSJack F Vogel ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data); 4450a69ed8dfSJack F Vogel if (ret_val) 4451a69ed8dfSJack F Vogel goto release; 44524edd8523SJack F Vogel 44538cfa0ad2SJack F Vogel data &= 0xBFFF; 44548cc64f1eSJack F Vogel ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset * 2 + 1, 44558cfa0ad2SJack F Vogel (u8)(data >> 8)); 4456a69ed8dfSJack F Vogel if (ret_val) 4457a69ed8dfSJack F Vogel goto release; 44588cfa0ad2SJack F Vogel 44596ab6bfe3SJack F Vogel /* And invalidate the previously valid segment by setting 44608cfa0ad2SJack F Vogel * its signature word (0x13) high_byte to 0b. This can be 44618cfa0ad2SJack F Vogel * done without an erase because flash erase sets all bits 44628cfa0ad2SJack F Vogel * to 1's. We can write 1's to 0's without an erase 44638cfa0ad2SJack F Vogel */ 44648cfa0ad2SJack F Vogel act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1; 44658cc64f1eSJack F Vogel 44668cfa0ad2SJack F Vogel ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0); 44678cc64f1eSJack F Vogel 4468a69ed8dfSJack F Vogel if (ret_val) 4469a69ed8dfSJack F Vogel goto release; 44708cfa0ad2SJack F Vogel 44718cfa0ad2SJack F Vogel /* Great! Everything worked, we can now clear the cached entries. */ 44728cfa0ad2SJack F Vogel for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) { 44738cfa0ad2SJack F Vogel dev_spec->shadow_ram[i].modified = FALSE; 44748cfa0ad2SJack F Vogel dev_spec->shadow_ram[i].value = 0xFFFF; 44758cfa0ad2SJack F Vogel } 44768cfa0ad2SJack F Vogel 4477a69ed8dfSJack F Vogel release: 44788cfa0ad2SJack F Vogel nvm->ops.release(hw); 44798cfa0ad2SJack F Vogel 44806ab6bfe3SJack F Vogel /* Reload the EEPROM, or else modifications will not appear 44818cfa0ad2SJack F Vogel * until after the next adapter reset. 44828cfa0ad2SJack F Vogel */ 4483a69ed8dfSJack F Vogel if (!ret_val) { 44848cfa0ad2SJack F Vogel nvm->ops.reload(hw); 44858cfa0ad2SJack F Vogel msec_delay(10); 4486a69ed8dfSJack F Vogel } 44878cfa0ad2SJack F Vogel 44888cfa0ad2SJack F Vogel out: 4489d035aa2dSJack F Vogel if (ret_val) 4490d035aa2dSJack F Vogel DEBUGOUT1("NVM update error: %d\n", ret_val); 4491d035aa2dSJack F Vogel 44928cfa0ad2SJack F Vogel return ret_val; 44938cfa0ad2SJack F Vogel } 44948cfa0ad2SJack F Vogel 44958cfa0ad2SJack F Vogel /** 44968cfa0ad2SJack F Vogel * e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum 44978cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 44988cfa0ad2SJack F Vogel * 44998cfa0ad2SJack F Vogel * Check to see if checksum needs to be fixed by reading bit 6 in word 0x19. 4500daf9197cSJack F Vogel * If the bit is 0, that the EEPROM had been modified, but the checksum was not 4501daf9197cSJack F Vogel * calculated, in which case we need to calculate the checksum and set bit 6. 45028cfa0ad2SJack F Vogel **/ 45038cfa0ad2SJack F Vogel static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw) 45048cfa0ad2SJack F Vogel { 45056ab6bfe3SJack F Vogel s32 ret_val; 45068cfa0ad2SJack F Vogel u16 data; 45076ab6bfe3SJack F Vogel u16 word; 45086ab6bfe3SJack F Vogel u16 valid_csum_mask; 45098cfa0ad2SJack F Vogel 45108cfa0ad2SJack F Vogel DEBUGFUNC("e1000_validate_nvm_checksum_ich8lan"); 45118cfa0ad2SJack F Vogel 45126ab6bfe3SJack F Vogel /* Read NVM and check Invalid Image CSUM bit. If this bit is 0, 45136ab6bfe3SJack F Vogel * the checksum needs to be fixed. This bit is an indication that 45146ab6bfe3SJack F Vogel * the NVM was prepared by OEM software and did not calculate 45156ab6bfe3SJack F Vogel * the checksum...a likely scenario. 45168cfa0ad2SJack F Vogel */ 45176ab6bfe3SJack F Vogel switch (hw->mac.type) { 45186ab6bfe3SJack F Vogel case e1000_pch_lpt: 4519c80429ceSEric Joyner case e1000_pch_spt: 45206fe4c0a0SSean Bruno case e1000_pch_cnp: 452159690eabSKevin Bowling case e1000_pch_tgp: 452259690eabSKevin Bowling case e1000_pch_adp: 452359690eabSKevin Bowling case e1000_pch_mtp: 45246ab6bfe3SJack F Vogel word = NVM_COMPAT; 45256ab6bfe3SJack F Vogel valid_csum_mask = NVM_COMPAT_VALID_CSUM; 45266ab6bfe3SJack F Vogel break; 45276ab6bfe3SJack F Vogel default: 45286ab6bfe3SJack F Vogel word = NVM_FUTURE_INIT_WORD1; 45296ab6bfe3SJack F Vogel valid_csum_mask = NVM_FUTURE_INIT_WORD1_VALID_CSUM; 45306ab6bfe3SJack F Vogel break; 45318cfa0ad2SJack F Vogel } 45328cfa0ad2SJack F Vogel 45336ab6bfe3SJack F Vogel ret_val = hw->nvm.ops.read(hw, word, 1, &data); 45346ab6bfe3SJack F Vogel if (ret_val) 45358cfa0ad2SJack F Vogel return ret_val; 45366ab6bfe3SJack F Vogel 45376ab6bfe3SJack F Vogel if (!(data & valid_csum_mask)) { 45386ab6bfe3SJack F Vogel data |= valid_csum_mask; 45396ab6bfe3SJack F Vogel ret_val = hw->nvm.ops.write(hw, word, 1, &data); 45406ab6bfe3SJack F Vogel if (ret_val) 45416ab6bfe3SJack F Vogel return ret_val; 45426ab6bfe3SJack F Vogel ret_val = hw->nvm.ops.update(hw); 45436ab6bfe3SJack F Vogel if (ret_val) 45446ab6bfe3SJack F Vogel return ret_val; 45456ab6bfe3SJack F Vogel } 45466ab6bfe3SJack F Vogel 45476ab6bfe3SJack F Vogel return e1000_validate_nvm_checksum_generic(hw); 45488cfa0ad2SJack F Vogel } 45498cfa0ad2SJack F Vogel 45508cfa0ad2SJack F Vogel /** 45518cfa0ad2SJack F Vogel * e1000_write_flash_data_ich8lan - Writes bytes to the NVM 45528cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 45538cfa0ad2SJack F Vogel * @offset: The offset (in bytes) of the byte/word to read. 45548cfa0ad2SJack F Vogel * @size: Size of data to read, 1=byte 2=word 45558cfa0ad2SJack F Vogel * @data: The byte(s) to write to the NVM. 45568cfa0ad2SJack F Vogel * 45578cfa0ad2SJack F Vogel * Writes one/two bytes to the NVM using the flash access registers. 45588cfa0ad2SJack F Vogel **/ 45598cfa0ad2SJack F Vogel static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, 45608cfa0ad2SJack F Vogel u8 size, u16 data) 45618cfa0ad2SJack F Vogel { 45628cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts; 45638cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl hsflctl; 45648cfa0ad2SJack F Vogel u32 flash_linear_addr; 45658cfa0ad2SJack F Vogel u32 flash_data = 0; 45666ab6bfe3SJack F Vogel s32 ret_val; 45678cfa0ad2SJack F Vogel u8 count = 0; 45688cfa0ad2SJack F Vogel 45698cfa0ad2SJack F Vogel DEBUGFUNC("e1000_write_ich8_data"); 45708cfa0ad2SJack F Vogel 4571295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt) { 4572c80429ceSEric Joyner if (size != 4 || offset > ICH_FLASH_LINEAR_ADDR_MASK) 4573c80429ceSEric Joyner return -E1000_ERR_NVM; 4574c80429ceSEric Joyner } else { 45758cc64f1eSJack F Vogel if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK) 45766ab6bfe3SJack F Vogel return -E1000_ERR_NVM; 4577c80429ceSEric Joyner } 45788cfa0ad2SJack F Vogel 45797609433eSJack F Vogel flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) + 45807609433eSJack F Vogel hw->nvm.flash_base_addr); 45818cfa0ad2SJack F Vogel 45828cfa0ad2SJack F Vogel do { 45838cfa0ad2SJack F Vogel usec_delay(1); 45848cfa0ad2SJack F Vogel /* Steps */ 45858cfa0ad2SJack F Vogel ret_val = e1000_flash_cycle_init_ich8lan(hw); 45868cfa0ad2SJack F Vogel if (ret_val != E1000_SUCCESS) 45878cfa0ad2SJack F Vogel break; 4588c80429ceSEric Joyner /* In SPT, This register is in Lan memory space, not 4589c80429ceSEric Joyner * flash. Therefore, only 32 bit access is supported 4590c80429ceSEric Joyner */ 4591295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt) 4592c80429ceSEric Joyner hsflctl.regval = 4593c80429ceSEric Joyner E1000_READ_FLASH_REG(hw, ICH_FLASH_HSFSTS)>>16; 4594c80429ceSEric Joyner else 4595c80429ceSEric Joyner hsflctl.regval = 4596c80429ceSEric Joyner E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL); 45978cc64f1eSJack F Vogel 45988cfa0ad2SJack F Vogel /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ 45998cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.fldbcount = size - 1; 46008cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE; 4601c80429ceSEric Joyner /* In SPT, This register is in Lan memory space, 4602c80429ceSEric Joyner * not flash. Therefore, only 32 bit access is 4603c80429ceSEric Joyner * supported 4604c80429ceSEric Joyner */ 4605295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt) 4606c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, 4607c80429ceSEric Joyner hsflctl.regval << 16); 4608c80429ceSEric Joyner else 4609c80429ceSEric Joyner E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, 4610c80429ceSEric Joyner hsflctl.regval); 46118cfa0ad2SJack F Vogel 46128cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr); 46138cfa0ad2SJack F Vogel 46148cfa0ad2SJack F Vogel if (size == 1) 46158cfa0ad2SJack F Vogel flash_data = (u32)data & 0x00FF; 46168cfa0ad2SJack F Vogel else 46178cfa0ad2SJack F Vogel flash_data = (u32)data; 46188cfa0ad2SJack F Vogel 46198cfa0ad2SJack F Vogel E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, flash_data); 46208cfa0ad2SJack F Vogel 46216ab6bfe3SJack F Vogel /* check if FCERR is set to 1 , if set to 1, clear it 46228cfa0ad2SJack F Vogel * and try the whole sequence a few more times else done 46238cfa0ad2SJack F Vogel */ 46247609433eSJack F Vogel ret_val = 46257609433eSJack F Vogel e1000_flash_cycle_ich8lan(hw, 46268cfa0ad2SJack F Vogel ICH_FLASH_WRITE_COMMAND_TIMEOUT); 4627daf9197cSJack F Vogel if (ret_val == E1000_SUCCESS) 46288cfa0ad2SJack F Vogel break; 4629daf9197cSJack F Vogel 46306ab6bfe3SJack F Vogel /* If we're here, then things are most likely 46318cfa0ad2SJack F Vogel * completely hosed, but if the error condition 46328cfa0ad2SJack F Vogel * is detected, it won't hurt to give it another 46338cfa0ad2SJack F Vogel * try...ICH_FLASH_CYCLE_REPEAT_COUNT times. 46348cfa0ad2SJack F Vogel */ 4635daf9197cSJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); 46366ab6bfe3SJack F Vogel if (hsfsts.hsf_status.flcerr) 46378cfa0ad2SJack F Vogel /* Repeat for some time before giving up. */ 46388cfa0ad2SJack F Vogel continue; 46396ab6bfe3SJack F Vogel if (!hsfsts.hsf_status.flcdone) { 46404dab5c37SJack F Vogel DEBUGOUT("Timeout error - flash cycle did not complete.\n"); 46418cfa0ad2SJack F Vogel break; 46428cfa0ad2SJack F Vogel } 46438cfa0ad2SJack F Vogel } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); 46448cfa0ad2SJack F Vogel 46458cfa0ad2SJack F Vogel return ret_val; 46468cfa0ad2SJack F Vogel } 46478cfa0ad2SJack F Vogel 4648c80429ceSEric Joyner /** 4649c80429ceSEric Joyner * e1000_write_flash_data32_ich8lan - Writes 4 bytes to the NVM 4650c80429ceSEric Joyner * @hw: pointer to the HW structure 4651c80429ceSEric Joyner * @offset: The offset (in bytes) of the dwords to read. 4652c80429ceSEric Joyner * @data: The 4 bytes to write to the NVM. 4653c80429ceSEric Joyner * 4654c80429ceSEric Joyner * Writes one/two/four bytes to the NVM using the flash access registers. 4655c80429ceSEric Joyner **/ 4656c80429ceSEric Joyner static s32 e1000_write_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset, 4657c80429ceSEric Joyner u32 data) 4658c80429ceSEric Joyner { 4659c80429ceSEric Joyner union ich8_hws_flash_status hsfsts; 4660c80429ceSEric Joyner union ich8_hws_flash_ctrl hsflctl; 4661c80429ceSEric Joyner u32 flash_linear_addr; 4662c80429ceSEric Joyner s32 ret_val; 4663c80429ceSEric Joyner u8 count = 0; 4664c80429ceSEric Joyner 4665c80429ceSEric Joyner DEBUGFUNC("e1000_write_flash_data32_ich8lan"); 4666c80429ceSEric Joyner 4667295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt) { 4668c80429ceSEric Joyner if (offset > ICH_FLASH_LINEAR_ADDR_MASK) 4669c80429ceSEric Joyner return -E1000_ERR_NVM; 4670c80429ceSEric Joyner } 4671c80429ceSEric Joyner flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) + 4672c80429ceSEric Joyner hw->nvm.flash_base_addr); 4673c80429ceSEric Joyner do { 4674c80429ceSEric Joyner usec_delay(1); 4675c80429ceSEric Joyner /* Steps */ 4676c80429ceSEric Joyner ret_val = e1000_flash_cycle_init_ich8lan(hw); 4677c80429ceSEric Joyner if (ret_val != E1000_SUCCESS) 4678c80429ceSEric Joyner break; 4679c80429ceSEric Joyner 4680c80429ceSEric Joyner /* In SPT, This register is in Lan memory space, not 4681c80429ceSEric Joyner * flash. Therefore, only 32 bit access is supported 4682c80429ceSEric Joyner */ 4683295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt) 4684c80429ceSEric Joyner hsflctl.regval = E1000_READ_FLASH_REG(hw, 4685c80429ceSEric Joyner ICH_FLASH_HSFSTS) 4686c80429ceSEric Joyner >> 16; 4687c80429ceSEric Joyner else 4688c80429ceSEric Joyner hsflctl.regval = E1000_READ_FLASH_REG16(hw, 4689c80429ceSEric Joyner ICH_FLASH_HSFCTL); 4690c80429ceSEric Joyner 4691c80429ceSEric Joyner hsflctl.hsf_ctrl.fldbcount = sizeof(u32) - 1; 4692c80429ceSEric Joyner hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE; 4693c80429ceSEric Joyner 4694c80429ceSEric Joyner /* In SPT, This register is in Lan memory space, 4695c80429ceSEric Joyner * not flash. Therefore, only 32 bit access is 4696c80429ceSEric Joyner * supported 4697c80429ceSEric Joyner */ 4698295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt) 4699c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, 4700c80429ceSEric Joyner hsflctl.regval << 16); 4701c80429ceSEric Joyner else 4702c80429ceSEric Joyner E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, 4703c80429ceSEric Joyner hsflctl.regval); 4704c80429ceSEric Joyner 4705c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr); 4706c80429ceSEric Joyner 4707c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, data); 4708c80429ceSEric Joyner 4709c80429ceSEric Joyner /* check if FCERR is set to 1 , if set to 1, clear it 4710c80429ceSEric Joyner * and try the whole sequence a few more times else done 4711c80429ceSEric Joyner */ 4712c80429ceSEric Joyner ret_val = e1000_flash_cycle_ich8lan(hw, 4713c80429ceSEric Joyner ICH_FLASH_WRITE_COMMAND_TIMEOUT); 4714c80429ceSEric Joyner 4715c80429ceSEric Joyner if (ret_val == E1000_SUCCESS) 4716c80429ceSEric Joyner break; 4717c80429ceSEric Joyner 4718c80429ceSEric Joyner /* If we're here, then things are most likely 4719c80429ceSEric Joyner * completely hosed, but if the error condition 4720c80429ceSEric Joyner * is detected, it won't hurt to give it another 4721c80429ceSEric Joyner * try...ICH_FLASH_CYCLE_REPEAT_COUNT times. 4722c80429ceSEric Joyner */ 4723c80429ceSEric Joyner hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); 4724c80429ceSEric Joyner 4725c80429ceSEric Joyner if (hsfsts.hsf_status.flcerr) 4726c80429ceSEric Joyner /* Repeat for some time before giving up. */ 4727c80429ceSEric Joyner continue; 4728c80429ceSEric Joyner if (!hsfsts.hsf_status.flcdone) { 4729c80429ceSEric Joyner DEBUGOUT("Timeout error - flash cycle did not complete.\n"); 4730c80429ceSEric Joyner break; 4731c80429ceSEric Joyner } 4732c80429ceSEric Joyner } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); 4733c80429ceSEric Joyner 4734c80429ceSEric Joyner return ret_val; 4735c80429ceSEric Joyner } 47368cc64f1eSJack F Vogel 47378cfa0ad2SJack F Vogel /** 47388cfa0ad2SJack F Vogel * e1000_write_flash_byte_ich8lan - Write a single byte to NVM 47398cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 47408cfa0ad2SJack F Vogel * @offset: The index of the byte to read. 47418cfa0ad2SJack F Vogel * @data: The byte to write to the NVM. 47428cfa0ad2SJack F Vogel * 47438cfa0ad2SJack F Vogel * Writes a single byte to the NVM using the flash access registers. 47448cfa0ad2SJack F Vogel **/ 47458cfa0ad2SJack F Vogel static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, 47468cfa0ad2SJack F Vogel u8 data) 47478cfa0ad2SJack F Vogel { 47488cfa0ad2SJack F Vogel u16 word = (u16)data; 47498cfa0ad2SJack F Vogel 47508cfa0ad2SJack F Vogel DEBUGFUNC("e1000_write_flash_byte_ich8lan"); 47518cfa0ad2SJack F Vogel 47528cfa0ad2SJack F Vogel return e1000_write_flash_data_ich8lan(hw, offset, 1, word); 47538cfa0ad2SJack F Vogel } 47548cfa0ad2SJack F Vogel 4755c80429ceSEric Joyner /** 4756c80429ceSEric Joyner * e1000_retry_write_flash_dword_ich8lan - Writes a dword to NVM 4757c80429ceSEric Joyner * @hw: pointer to the HW structure 4758c80429ceSEric Joyner * @offset: The offset of the word to write. 4759c80429ceSEric Joyner * @dword: The dword to write to the NVM. 4760c80429ceSEric Joyner * 4761c80429ceSEric Joyner * Writes a single dword to the NVM using the flash access registers. 4762c80429ceSEric Joyner * Goes through a retry algorithm before giving up. 4763c80429ceSEric Joyner **/ 4764c80429ceSEric Joyner static s32 e1000_retry_write_flash_dword_ich8lan(struct e1000_hw *hw, 4765c80429ceSEric Joyner u32 offset, u32 dword) 4766c80429ceSEric Joyner { 4767c80429ceSEric Joyner s32 ret_val; 4768c80429ceSEric Joyner u16 program_retries; 47698cc64f1eSJack F Vogel 4770c80429ceSEric Joyner DEBUGFUNC("e1000_retry_write_flash_dword_ich8lan"); 4771c80429ceSEric Joyner 4772c80429ceSEric Joyner /* Must convert word offset into bytes. */ 4773c80429ceSEric Joyner offset <<= 1; 4774c80429ceSEric Joyner 4775c80429ceSEric Joyner ret_val = e1000_write_flash_data32_ich8lan(hw, offset, dword); 4776c80429ceSEric Joyner 4777c80429ceSEric Joyner if (!ret_val) 4778c80429ceSEric Joyner return ret_val; 4779c80429ceSEric Joyner for (program_retries = 0; program_retries < 100; program_retries++) { 4780c80429ceSEric Joyner DEBUGOUT2("Retrying Byte %8.8X at offset %u\n", dword, offset); 4781c80429ceSEric Joyner usec_delay(100); 4782c80429ceSEric Joyner ret_val = e1000_write_flash_data32_ich8lan(hw, offset, dword); 4783c80429ceSEric Joyner if (ret_val == E1000_SUCCESS) 4784c80429ceSEric Joyner break; 4785c80429ceSEric Joyner } 4786c80429ceSEric Joyner if (program_retries == 100) 4787c80429ceSEric Joyner return -E1000_ERR_NVM; 4788c80429ceSEric Joyner 4789c80429ceSEric Joyner return E1000_SUCCESS; 4790c80429ceSEric Joyner } 47918cc64f1eSJack F Vogel 47928cfa0ad2SJack F Vogel /** 47938cfa0ad2SJack F Vogel * e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM 47948cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 47958cfa0ad2SJack F Vogel * @offset: The offset of the byte to write. 47968cfa0ad2SJack F Vogel * @byte: The byte to write to the NVM. 47978cfa0ad2SJack F Vogel * 47988cfa0ad2SJack F Vogel * Writes a single byte to the NVM using the flash access registers. 47998cfa0ad2SJack F Vogel * Goes through a retry algorithm before giving up. 48008cfa0ad2SJack F Vogel **/ 48018cfa0ad2SJack F Vogel static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, 48028cfa0ad2SJack F Vogel u32 offset, u8 byte) 48038cfa0ad2SJack F Vogel { 48048cfa0ad2SJack F Vogel s32 ret_val; 48058cfa0ad2SJack F Vogel u16 program_retries; 48068cfa0ad2SJack F Vogel 48078cfa0ad2SJack F Vogel DEBUGFUNC("e1000_retry_write_flash_byte_ich8lan"); 48088cfa0ad2SJack F Vogel 48098cfa0ad2SJack F Vogel ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte); 48106ab6bfe3SJack F Vogel if (!ret_val) 48116ab6bfe3SJack F Vogel return ret_val; 48128cfa0ad2SJack F Vogel 48138cfa0ad2SJack F Vogel for (program_retries = 0; program_retries < 100; program_retries++) { 48148cfa0ad2SJack F Vogel DEBUGOUT2("Retrying Byte %2.2X at offset %u\n", byte, offset); 48158cfa0ad2SJack F Vogel usec_delay(100); 48168cfa0ad2SJack F Vogel ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte); 48178cfa0ad2SJack F Vogel if (ret_val == E1000_SUCCESS) 48188cfa0ad2SJack F Vogel break; 48198cfa0ad2SJack F Vogel } 48206ab6bfe3SJack F Vogel if (program_retries == 100) 48216ab6bfe3SJack F Vogel return -E1000_ERR_NVM; 48228cfa0ad2SJack F Vogel 48236ab6bfe3SJack F Vogel return E1000_SUCCESS; 48248cfa0ad2SJack F Vogel } 48258cfa0ad2SJack F Vogel 48268cfa0ad2SJack F Vogel /** 48278cfa0ad2SJack F Vogel * e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM 48288cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 48298cfa0ad2SJack F Vogel * @bank: 0 for first bank, 1 for second bank, etc. 48308cfa0ad2SJack F Vogel * 48318cfa0ad2SJack F Vogel * Erases the bank specified. Each bank is a 4k block. Banks are 0 based. 48328cfa0ad2SJack F Vogel * bank N is 4096 * N + flash_reg_addr. 48338cfa0ad2SJack F Vogel **/ 48348cfa0ad2SJack F Vogel static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank) 48358cfa0ad2SJack F Vogel { 48368cfa0ad2SJack F Vogel struct e1000_nvm_info *nvm = &hw->nvm; 48378cfa0ad2SJack F Vogel union ich8_hws_flash_status hsfsts; 48388cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl hsflctl; 48398cfa0ad2SJack F Vogel u32 flash_linear_addr; 48408cfa0ad2SJack F Vogel /* bank size is in 16bit words - adjust to bytes */ 48418cfa0ad2SJack F Vogel u32 flash_bank_size = nvm->flash_bank_size * 2; 48426ab6bfe3SJack F Vogel s32 ret_val; 48438cfa0ad2SJack F Vogel s32 count = 0; 48448cfa0ad2SJack F Vogel s32 j, iteration, sector_size; 48458cfa0ad2SJack F Vogel 48468cfa0ad2SJack F Vogel DEBUGFUNC("e1000_erase_flash_bank_ich8lan"); 48478cfa0ad2SJack F Vogel 48488cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS); 48498cfa0ad2SJack F Vogel 48506ab6bfe3SJack F Vogel /* Determine HW Sector size: Read BERASE bits of hw flash status 48518cfa0ad2SJack F Vogel * register 48528cfa0ad2SJack F Vogel * 00: The Hw sector is 256 bytes, hence we need to erase 16 48538cfa0ad2SJack F Vogel * consecutive sectors. The start index for the nth Hw sector 48548cfa0ad2SJack F Vogel * can be calculated as = bank * 4096 + n * 256 48558cfa0ad2SJack F Vogel * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector. 48568cfa0ad2SJack F Vogel * The start index for the nth Hw sector can be calculated 48578cfa0ad2SJack F Vogel * as = bank * 4096 48588cfa0ad2SJack F Vogel * 10: The Hw sector is 8K bytes, nth sector = bank * 8192 48598cfa0ad2SJack F Vogel * (ich9 only, otherwise error condition) 48608cfa0ad2SJack F Vogel * 11: The Hw sector is 64K bytes, nth sector = bank * 65536 48618cfa0ad2SJack F Vogel */ 48628cfa0ad2SJack F Vogel switch (hsfsts.hsf_status.berasesz) { 48638cfa0ad2SJack F Vogel case 0: 48648cfa0ad2SJack F Vogel /* Hw sector size 256 */ 48658cfa0ad2SJack F Vogel sector_size = ICH_FLASH_SEG_SIZE_256; 48668cfa0ad2SJack F Vogel iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256; 48678cfa0ad2SJack F Vogel break; 48688cfa0ad2SJack F Vogel case 1: 48698cfa0ad2SJack F Vogel sector_size = ICH_FLASH_SEG_SIZE_4K; 48709d81738fSJack F Vogel iteration = 1; 48718cfa0ad2SJack F Vogel break; 48728cfa0ad2SJack F Vogel case 2: 48738cfa0ad2SJack F Vogel sector_size = ICH_FLASH_SEG_SIZE_8K; 48748bd0025fSJack F Vogel iteration = 1; 48758cfa0ad2SJack F Vogel break; 48768cfa0ad2SJack F Vogel case 3: 48778cfa0ad2SJack F Vogel sector_size = ICH_FLASH_SEG_SIZE_64K; 48789d81738fSJack F Vogel iteration = 1; 48798cfa0ad2SJack F Vogel break; 48808cfa0ad2SJack F Vogel default: 48816ab6bfe3SJack F Vogel return -E1000_ERR_NVM; 48828cfa0ad2SJack F Vogel } 48838cfa0ad2SJack F Vogel 48848cfa0ad2SJack F Vogel /* Start with the base address, then add the sector offset. */ 48858cfa0ad2SJack F Vogel flash_linear_addr = hw->nvm.flash_base_addr; 48864edd8523SJack F Vogel flash_linear_addr += (bank) ? flash_bank_size : 0; 48878cfa0ad2SJack F Vogel 48888cfa0ad2SJack F Vogel for (j = 0; j < iteration; j++) { 48898cfa0ad2SJack F Vogel do { 48907609433eSJack F Vogel u32 timeout = ICH_FLASH_ERASE_COMMAND_TIMEOUT; 48917609433eSJack F Vogel 48928cfa0ad2SJack F Vogel /* Steps */ 48938cfa0ad2SJack F Vogel ret_val = e1000_flash_cycle_init_ich8lan(hw); 48948cfa0ad2SJack F Vogel if (ret_val) 48956ab6bfe3SJack F Vogel return ret_val; 48968cfa0ad2SJack F Vogel 48976ab6bfe3SJack F Vogel /* Write a value 11 (block Erase) in Flash 48988cfa0ad2SJack F Vogel * Cycle field in hw flash control 48998cfa0ad2SJack F Vogel */ 4900295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt) 49018cc64f1eSJack F Vogel hsflctl.regval = 4902c80429ceSEric Joyner E1000_READ_FLASH_REG(hw, 4903c80429ceSEric Joyner ICH_FLASH_HSFSTS)>>16; 4904c80429ceSEric Joyner else 4905c80429ceSEric Joyner hsflctl.regval = 4906c80429ceSEric Joyner E1000_READ_FLASH_REG16(hw, 4907c80429ceSEric Joyner ICH_FLASH_HSFCTL); 49088cc64f1eSJack F Vogel 49098cfa0ad2SJack F Vogel hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE; 4910295df609SEric Joyner if (hw->mac.type >= e1000_pch_spt) 4911c80429ceSEric Joyner E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS, 4912c80429ceSEric Joyner hsflctl.regval << 16); 4913c80429ceSEric Joyner else 4914daf9197cSJack F Vogel E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, 49158cfa0ad2SJack F Vogel hsflctl.regval); 49168cfa0ad2SJack F Vogel 49176ab6bfe3SJack F Vogel /* Write the last 24 bits of an index within the 49188cfa0ad2SJack F Vogel * block into Flash Linear address field in Flash 49198cfa0ad2SJack F Vogel * Address. 49208cfa0ad2SJack F Vogel */ 49218cfa0ad2SJack F Vogel flash_linear_addr += (j * sector_size); 4922daf9197cSJack F Vogel E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, 49238cfa0ad2SJack F Vogel flash_linear_addr); 49248cfa0ad2SJack F Vogel 49257609433eSJack F Vogel ret_val = e1000_flash_cycle_ich8lan(hw, timeout); 4926daf9197cSJack F Vogel if (ret_val == E1000_SUCCESS) 49278cfa0ad2SJack F Vogel break; 4928daf9197cSJack F Vogel 49296ab6bfe3SJack F Vogel /* Check if FCERR is set to 1. If 1, 49308cfa0ad2SJack F Vogel * clear it and try the whole sequence 49318cfa0ad2SJack F Vogel * a few more times else Done 49328cfa0ad2SJack F Vogel */ 49338cfa0ad2SJack F Vogel hsfsts.regval = E1000_READ_FLASH_REG16(hw, 49348cfa0ad2SJack F Vogel ICH_FLASH_HSFSTS); 49356ab6bfe3SJack F Vogel if (hsfsts.hsf_status.flcerr) 4936daf9197cSJack F Vogel /* repeat for some time before giving up */ 49378cfa0ad2SJack F Vogel continue; 49386ab6bfe3SJack F Vogel else if (!hsfsts.hsf_status.flcdone) 49396ab6bfe3SJack F Vogel return ret_val; 49408cfa0ad2SJack F Vogel } while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT); 49418cfa0ad2SJack F Vogel } 49428cfa0ad2SJack F Vogel 49436ab6bfe3SJack F Vogel return E1000_SUCCESS; 49448cfa0ad2SJack F Vogel } 49458cfa0ad2SJack F Vogel 49468cfa0ad2SJack F Vogel /** 49478cfa0ad2SJack F Vogel * e1000_valid_led_default_ich8lan - Set the default LED settings 49488cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 49498cfa0ad2SJack F Vogel * @data: Pointer to the LED settings 49508cfa0ad2SJack F Vogel * 49518cfa0ad2SJack F Vogel * Reads the LED default settings from the NVM to data. If the NVM LED 49528cfa0ad2SJack F Vogel * settings is all 0's or F's, set the LED default to a valid LED default 49538cfa0ad2SJack F Vogel * setting. 49548cfa0ad2SJack F Vogel **/ 49558cfa0ad2SJack F Vogel static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data) 49568cfa0ad2SJack F Vogel { 49578cfa0ad2SJack F Vogel s32 ret_val; 49588cfa0ad2SJack F Vogel 49598cfa0ad2SJack F Vogel DEBUGFUNC("e1000_valid_led_default_ich8lan"); 49608cfa0ad2SJack F Vogel 49618cfa0ad2SJack F Vogel ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data); 49628cfa0ad2SJack F Vogel if (ret_val) { 49638cfa0ad2SJack F Vogel DEBUGOUT("NVM Read Error\n"); 49646ab6bfe3SJack F Vogel return ret_val; 49658cfa0ad2SJack F Vogel } 49668cfa0ad2SJack F Vogel 49674dab5c37SJack F Vogel if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) 49688cfa0ad2SJack F Vogel *data = ID_LED_DEFAULT_ICH8LAN; 49698cfa0ad2SJack F Vogel 49706ab6bfe3SJack F Vogel return E1000_SUCCESS; 49718cfa0ad2SJack F Vogel } 49728cfa0ad2SJack F Vogel 49738cfa0ad2SJack F Vogel /** 49749d81738fSJack F Vogel * e1000_id_led_init_pchlan - store LED configurations 49759d81738fSJack F Vogel * @hw: pointer to the HW structure 49769d81738fSJack F Vogel * 49779d81738fSJack F Vogel * PCH does not control LEDs via the LEDCTL register, rather it uses 49789d81738fSJack F Vogel * the PHY LED configuration register. 49799d81738fSJack F Vogel * 49809d81738fSJack F Vogel * PCH also does not have an "always on" or "always off" mode which 49819d81738fSJack F Vogel * complicates the ID feature. Instead of using the "on" mode to indicate 49829d81738fSJack F Vogel * in ledctl_mode2 the LEDs to use for ID (see e1000_id_led_init_generic()), 49839d81738fSJack F Vogel * use "link_up" mode. The LEDs will still ID on request if there is no 49849d81738fSJack F Vogel * link based on logic in e1000_led_[on|off]_pchlan(). 49859d81738fSJack F Vogel **/ 49869d81738fSJack F Vogel static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw) 49879d81738fSJack F Vogel { 49889d81738fSJack F Vogel struct e1000_mac_info *mac = &hw->mac; 49899d81738fSJack F Vogel s32 ret_val; 49909d81738fSJack F Vogel const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP; 49919d81738fSJack F Vogel const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT; 49929d81738fSJack F Vogel u16 data, i, temp, shift; 49939d81738fSJack F Vogel 49949d81738fSJack F Vogel DEBUGFUNC("e1000_id_led_init_pchlan"); 49959d81738fSJack F Vogel 49969d81738fSJack F Vogel /* Get default ID LED modes */ 49979d81738fSJack F Vogel ret_val = hw->nvm.ops.valid_led_default(hw, &data); 49989d81738fSJack F Vogel if (ret_val) 49996ab6bfe3SJack F Vogel return ret_val; 50009d81738fSJack F Vogel 50019d81738fSJack F Vogel mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL); 50029d81738fSJack F Vogel mac->ledctl_mode1 = mac->ledctl_default; 50039d81738fSJack F Vogel mac->ledctl_mode2 = mac->ledctl_default; 50049d81738fSJack F Vogel 50059d81738fSJack F Vogel for (i = 0; i < 4; i++) { 50069d81738fSJack F Vogel temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK; 50079d81738fSJack F Vogel shift = (i * 5); 50089d81738fSJack F Vogel switch (temp) { 50099d81738fSJack F Vogel case ID_LED_ON1_DEF2: 50109d81738fSJack F Vogel case ID_LED_ON1_ON2: 50119d81738fSJack F Vogel case ID_LED_ON1_OFF2: 50129d81738fSJack F Vogel mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift); 50139d81738fSJack F Vogel mac->ledctl_mode1 |= (ledctl_on << shift); 50149d81738fSJack F Vogel break; 50159d81738fSJack F Vogel case ID_LED_OFF1_DEF2: 50169d81738fSJack F Vogel case ID_LED_OFF1_ON2: 50179d81738fSJack F Vogel case ID_LED_OFF1_OFF2: 50189d81738fSJack F Vogel mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift); 50199d81738fSJack F Vogel mac->ledctl_mode1 |= (ledctl_off << shift); 50209d81738fSJack F Vogel break; 50219d81738fSJack F Vogel default: 50229d81738fSJack F Vogel /* Do nothing */ 50239d81738fSJack F Vogel break; 50249d81738fSJack F Vogel } 50259d81738fSJack F Vogel switch (temp) { 50269d81738fSJack F Vogel case ID_LED_DEF1_ON2: 50279d81738fSJack F Vogel case ID_LED_ON1_ON2: 50289d81738fSJack F Vogel case ID_LED_OFF1_ON2: 50299d81738fSJack F Vogel mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift); 50309d81738fSJack F Vogel mac->ledctl_mode2 |= (ledctl_on << shift); 50319d81738fSJack F Vogel break; 50329d81738fSJack F Vogel case ID_LED_DEF1_OFF2: 50339d81738fSJack F Vogel case ID_LED_ON1_OFF2: 50349d81738fSJack F Vogel case ID_LED_OFF1_OFF2: 50359d81738fSJack F Vogel mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift); 50369d81738fSJack F Vogel mac->ledctl_mode2 |= (ledctl_off << shift); 50379d81738fSJack F Vogel break; 50389d81738fSJack F Vogel default: 50399d81738fSJack F Vogel /* Do nothing */ 50409d81738fSJack F Vogel break; 50419d81738fSJack F Vogel } 50429d81738fSJack F Vogel } 50439d81738fSJack F Vogel 50446ab6bfe3SJack F Vogel return E1000_SUCCESS; 50459d81738fSJack F Vogel } 50469d81738fSJack F Vogel 50479d81738fSJack F Vogel /** 50488cfa0ad2SJack F Vogel * e1000_get_bus_info_ich8lan - Get/Set the bus type and width 50498cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 50508cfa0ad2SJack F Vogel * 50518cfa0ad2SJack F Vogel * ICH8 use the PCI Express bus, but does not contain a PCI Express Capability 5052cef367e6SEitan Adler * register, so the bus width is hard coded. 50538cfa0ad2SJack F Vogel **/ 50548cfa0ad2SJack F Vogel static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw) 50558cfa0ad2SJack F Vogel { 50568cfa0ad2SJack F Vogel struct e1000_bus_info *bus = &hw->bus; 50578cfa0ad2SJack F Vogel s32 ret_val; 50588cfa0ad2SJack F Vogel 50598cfa0ad2SJack F Vogel DEBUGFUNC("e1000_get_bus_info_ich8lan"); 50608cfa0ad2SJack F Vogel 50618cfa0ad2SJack F Vogel ret_val = e1000_get_bus_info_pcie_generic(hw); 50628cfa0ad2SJack F Vogel 50636ab6bfe3SJack F Vogel /* ICH devices are "PCI Express"-ish. They have 50648cfa0ad2SJack F Vogel * a configuration space, but do not contain 50658cfa0ad2SJack F Vogel * PCI Express Capability registers, so bus width 50668cfa0ad2SJack F Vogel * must be hardcoded. 50678cfa0ad2SJack F Vogel */ 50688cfa0ad2SJack F Vogel if (bus->width == e1000_bus_width_unknown) 50698cfa0ad2SJack F Vogel bus->width = e1000_bus_width_pcie_x1; 50708cfa0ad2SJack F Vogel 50718cfa0ad2SJack F Vogel return ret_val; 50728cfa0ad2SJack F Vogel } 50738cfa0ad2SJack F Vogel 50748cfa0ad2SJack F Vogel /** 50758cfa0ad2SJack F Vogel * e1000_reset_hw_ich8lan - Reset the hardware 50768cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 50778cfa0ad2SJack F Vogel * 50788cfa0ad2SJack F Vogel * Does a full reset of the hardware which includes a reset of the PHY and 50798cfa0ad2SJack F Vogel * MAC. 50808cfa0ad2SJack F Vogel **/ 50818cfa0ad2SJack F Vogel static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) 50828cfa0ad2SJack F Vogel { 50834edd8523SJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 50846ab6bfe3SJack F Vogel u16 kum_cfg; 50856ab6bfe3SJack F Vogel u32 ctrl, reg; 50868cfa0ad2SJack F Vogel s32 ret_val; 5087*fc7682b1SKevin Bowling u16 pci_cfg; 50888cfa0ad2SJack F Vogel 50898cfa0ad2SJack F Vogel DEBUGFUNC("e1000_reset_hw_ich8lan"); 50908cfa0ad2SJack F Vogel 50916ab6bfe3SJack F Vogel /* Prevent the PCI-E bus from sticking if there is no TLP connection 50928cfa0ad2SJack F Vogel * on the last TLP read/write transaction when MAC is reset. 50938cfa0ad2SJack F Vogel */ 50948cfa0ad2SJack F Vogel ret_val = e1000_disable_pcie_master_generic(hw); 5095daf9197cSJack F Vogel if (ret_val) 50968cfa0ad2SJack F Vogel DEBUGOUT("PCI-E Master disable polling has failed.\n"); 50978cfa0ad2SJack F Vogel 50988cfa0ad2SJack F Vogel DEBUGOUT("Masking off all interrupts\n"); 50998cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); 51008cfa0ad2SJack F Vogel 51016ab6bfe3SJack F Vogel /* Disable the Transmit and Receive units. Then delay to allow 51028cfa0ad2SJack F Vogel * any pending transactions to complete before we hit the MAC 51038cfa0ad2SJack F Vogel * with the global reset. 51048cfa0ad2SJack F Vogel */ 51058cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_RCTL, 0); 51068cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP); 51078cfa0ad2SJack F Vogel E1000_WRITE_FLUSH(hw); 51088cfa0ad2SJack F Vogel 51098cfa0ad2SJack F Vogel msec_delay(10); 51108cfa0ad2SJack F Vogel 51118cfa0ad2SJack F Vogel /* Workaround for ICH8 bit corruption issue in FIFO memory */ 51128cfa0ad2SJack F Vogel if (hw->mac.type == e1000_ich8lan) { 51138cfa0ad2SJack F Vogel /* Set Tx and Rx buffer allocation to 8k apiece. */ 51148cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PBA, E1000_PBA_8K); 51158cfa0ad2SJack F Vogel /* Set Packet Buffer Size to 16k. */ 51168cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PBS, E1000_PBS_16K); 51178cfa0ad2SJack F Vogel } 51188cfa0ad2SJack F Vogel 51194edd8523SJack F Vogel if (hw->mac.type == e1000_pchlan) { 51204edd8523SJack F Vogel /* Save the NVM K1 bit setting*/ 51216ab6bfe3SJack F Vogel ret_val = e1000_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, &kum_cfg); 51224edd8523SJack F Vogel if (ret_val) 51234edd8523SJack F Vogel return ret_val; 51244edd8523SJack F Vogel 51256ab6bfe3SJack F Vogel if (kum_cfg & E1000_NVM_K1_ENABLE) 51264edd8523SJack F Vogel dev_spec->nvm_k1_enabled = TRUE; 51274edd8523SJack F Vogel else 51284edd8523SJack F Vogel dev_spec->nvm_k1_enabled = FALSE; 51294edd8523SJack F Vogel } 51304edd8523SJack F Vogel 51318cfa0ad2SJack F Vogel ctrl = E1000_READ_REG(hw, E1000_CTRL); 51328cfa0ad2SJack F Vogel 51337d9119bdSJack F Vogel if (!hw->phy.ops.check_reset_block(hw)) { 51346ab6bfe3SJack F Vogel /* Full-chip reset requires MAC and PHY reset at the same 51358cfa0ad2SJack F Vogel * time to make sure the interface between MAC and the 51368cfa0ad2SJack F Vogel * external PHY is reset. 51378cfa0ad2SJack F Vogel */ 51388cfa0ad2SJack F Vogel ctrl |= E1000_CTRL_PHY_RST; 51397d9119bdSJack F Vogel 51406ab6bfe3SJack F Vogel /* Gate automatic PHY configuration by hardware on 51417d9119bdSJack F Vogel * non-managed 82579 51427d9119bdSJack F Vogel */ 51437d9119bdSJack F Vogel if ((hw->mac.type == e1000_pch2lan) && 51447d9119bdSJack F Vogel !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID)) 51457d9119bdSJack F Vogel e1000_gate_hw_phy_config_ich8lan(hw, TRUE); 51468cfa0ad2SJack F Vogel } 51478cfa0ad2SJack F Vogel ret_val = e1000_acquire_swflag_ich8lan(hw); 5148*fc7682b1SKevin Bowling 5149*fc7682b1SKevin Bowling /* Read from EXTCNF_CTRL in e1000_acquire_swflag_ich8lan function 5150*fc7682b1SKevin Bowling * may occur during global reset and cause system hang. 5151*fc7682b1SKevin Bowling * Configuration space access creates the needed delay. 5152*fc7682b1SKevin Bowling * Write to E1000_STRAP RO register E1000_PCI_VENDOR_ID_REGISTER value 5153*fc7682b1SKevin Bowling * insures configuration space read is done before global reset. 5154*fc7682b1SKevin Bowling */ 5155*fc7682b1SKevin Bowling e1000_read_pci_cfg(hw, E1000_PCI_VENDOR_ID_REGISTER, &pci_cfg); 5156*fc7682b1SKevin Bowling E1000_WRITE_REG(hw, E1000_STRAP, pci_cfg); 5157daf9197cSJack F Vogel DEBUGOUT("Issuing a global reset to ich8lan\n"); 51588cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_RST)); 51594dab5c37SJack F Vogel /* cannot issue a flush here because it hangs the hardware */ 51608cfa0ad2SJack F Vogel msec_delay(20); 51618cfa0ad2SJack F Vogel 5162*fc7682b1SKevin Bowling /* Configuration space access improve HW level time sync mechanism. 5163*fc7682b1SKevin Bowling * Write to E1000_STRAP RO register E1000_PCI_VENDOR_ID_REGISTER 5164*fc7682b1SKevin Bowling * value to insure configuration space read is done 5165*fc7682b1SKevin Bowling * before any access to mac register. 5166*fc7682b1SKevin Bowling */ 5167*fc7682b1SKevin Bowling e1000_read_pci_cfg(hw, E1000_PCI_VENDOR_ID_REGISTER, &pci_cfg); 5168*fc7682b1SKevin Bowling E1000_WRITE_REG(hw, E1000_STRAP, pci_cfg); 5169*fc7682b1SKevin Bowling 51706ab6bfe3SJack F Vogel /* Set Phy Config Counter to 50msec */ 51716ab6bfe3SJack F Vogel if (hw->mac.type == e1000_pch2lan) { 51726ab6bfe3SJack F Vogel reg = E1000_READ_REG(hw, E1000_FEXTNVM3); 51736ab6bfe3SJack F Vogel reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK; 51746ab6bfe3SJack F Vogel reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC; 51756ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM3, reg); 51766ab6bfe3SJack F Vogel } 51776ab6bfe3SJack F Vogel 51789d81738fSJack F Vogel 51797d9119bdSJack F Vogel if (ctrl & E1000_CTRL_PHY_RST) { 51809d81738fSJack F Vogel ret_val = hw->phy.ops.get_cfg_done(hw); 51814edd8523SJack F Vogel if (ret_val) 51826ab6bfe3SJack F Vogel return ret_val; 51834edd8523SJack F Vogel 51847d9119bdSJack F Vogel ret_val = e1000_post_phy_reset_ich8lan(hw); 51854edd8523SJack F Vogel if (ret_val) 51866ab6bfe3SJack F Vogel return ret_val; 51877d9119bdSJack F Vogel } 51887d9119bdSJack F Vogel 51896ab6bfe3SJack F Vogel /* For PCH, this write will make sure that any noise 51904edd8523SJack F Vogel * will be detected as a CRC error and be dropped rather than show up 51914edd8523SJack F Vogel * as a bad packet to the DMA engine. 51924edd8523SJack F Vogel */ 51934edd8523SJack F Vogel if (hw->mac.type == e1000_pchlan) 51944edd8523SJack F Vogel E1000_WRITE_REG(hw, E1000_CRC_OFFSET, 0x65656565); 51958cfa0ad2SJack F Vogel 51968cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); 5197730d3130SJack F Vogel E1000_READ_REG(hw, E1000_ICR); 51988cfa0ad2SJack F Vogel 51996ab6bfe3SJack F Vogel reg = E1000_READ_REG(hw, E1000_KABGTXD); 52006ab6bfe3SJack F Vogel reg |= E1000_KABGTXD_BGSQLBIAS; 52016ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_KABGTXD, reg); 52028cfa0ad2SJack F Vogel 52036ab6bfe3SJack F Vogel return E1000_SUCCESS; 52048cfa0ad2SJack F Vogel } 52058cfa0ad2SJack F Vogel 52068cfa0ad2SJack F Vogel /** 52078cfa0ad2SJack F Vogel * e1000_init_hw_ich8lan - Initialize the hardware 52088cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 52098cfa0ad2SJack F Vogel * 52108cfa0ad2SJack F Vogel * Prepares the hardware for transmit and receive by doing the following: 52118cfa0ad2SJack F Vogel * - initialize hardware bits 52128cfa0ad2SJack F Vogel * - initialize LED identification 52138cfa0ad2SJack F Vogel * - setup receive address registers 52148cfa0ad2SJack F Vogel * - setup flow control 52158cfa0ad2SJack F Vogel * - setup transmit descriptors 52168cfa0ad2SJack F Vogel * - clear statistics 52178cfa0ad2SJack F Vogel **/ 52188cfa0ad2SJack F Vogel static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw) 52198cfa0ad2SJack F Vogel { 52208cfa0ad2SJack F Vogel struct e1000_mac_info *mac = &hw->mac; 52218cfa0ad2SJack F Vogel u32 ctrl_ext, txdctl, snoop; 52228cfa0ad2SJack F Vogel s32 ret_val; 52238cfa0ad2SJack F Vogel u16 i; 52248cfa0ad2SJack F Vogel 52258cfa0ad2SJack F Vogel DEBUGFUNC("e1000_init_hw_ich8lan"); 52268cfa0ad2SJack F Vogel 52278cfa0ad2SJack F Vogel e1000_initialize_hw_bits_ich8lan(hw); 52288cfa0ad2SJack F Vogel 52298cfa0ad2SJack F Vogel /* Initialize identification LED */ 5230d035aa2dSJack F Vogel ret_val = mac->ops.id_led_init(hw); 52316ab6bfe3SJack F Vogel /* An error is not fatal and we should not stop init due to this */ 5232d035aa2dSJack F Vogel if (ret_val) 5233d035aa2dSJack F Vogel DEBUGOUT("Error initializing identification LED\n"); 52348cfa0ad2SJack F Vogel 52358cfa0ad2SJack F Vogel /* Setup the receive address. */ 52368cfa0ad2SJack F Vogel e1000_init_rx_addrs_generic(hw, mac->rar_entry_count); 52378cfa0ad2SJack F Vogel 52388cfa0ad2SJack F Vogel /* Zero out the Multicast HASH table */ 52398cfa0ad2SJack F Vogel DEBUGOUT("Zeroing the MTA\n"); 52408cfa0ad2SJack F Vogel for (i = 0; i < mac->mta_reg_count; i++) 52418cfa0ad2SJack F Vogel E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); 52428cfa0ad2SJack F Vogel 52436ab6bfe3SJack F Vogel /* The 82578 Rx buffer will stall if wakeup is enabled in host and 52444dab5c37SJack F Vogel * the ME. Disable wakeup by clearing the host wakeup bit. 52459d81738fSJack F Vogel * Reset the phy after disabling host wakeup to reset the Rx buffer. 52469d81738fSJack F Vogel */ 52479d81738fSJack F Vogel if (hw->phy.type == e1000_phy_82578) { 52484dab5c37SJack F Vogel hw->phy.ops.read_reg(hw, BM_PORT_GEN_CFG, &i); 52494dab5c37SJack F Vogel i &= ~BM_WUC_HOST_WU_BIT; 52504dab5c37SJack F Vogel hw->phy.ops.write_reg(hw, BM_PORT_GEN_CFG, i); 52519d81738fSJack F Vogel ret_val = e1000_phy_hw_reset_ich8lan(hw); 52529d81738fSJack F Vogel if (ret_val) 52539d81738fSJack F Vogel return ret_val; 52549d81738fSJack F Vogel } 52559d81738fSJack F Vogel 52568cfa0ad2SJack F Vogel /* Setup link and flow control */ 52578cfa0ad2SJack F Vogel ret_val = mac->ops.setup_link(hw); 52588cfa0ad2SJack F Vogel 52598cfa0ad2SJack F Vogel /* Set the transmit descriptor write-back policy for both queues */ 52608cfa0ad2SJack F Vogel txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0)); 52617609433eSJack F Vogel txdctl = ((txdctl & ~E1000_TXDCTL_WTHRESH) | 52627609433eSJack F Vogel E1000_TXDCTL_FULL_TX_DESC_WB); 52637609433eSJack F Vogel txdctl = ((txdctl & ~E1000_TXDCTL_PTHRESH) | 52647609433eSJack F Vogel E1000_TXDCTL_MAX_TX_DESC_PREFETCH); 52658cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl); 52668cfa0ad2SJack F Vogel txdctl = E1000_READ_REG(hw, E1000_TXDCTL(1)); 52677609433eSJack F Vogel txdctl = ((txdctl & ~E1000_TXDCTL_WTHRESH) | 52687609433eSJack F Vogel E1000_TXDCTL_FULL_TX_DESC_WB); 52697609433eSJack F Vogel txdctl = ((txdctl & ~E1000_TXDCTL_PTHRESH) | 52707609433eSJack F Vogel E1000_TXDCTL_MAX_TX_DESC_PREFETCH); 52718cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TXDCTL(1), txdctl); 52728cfa0ad2SJack F Vogel 52736ab6bfe3SJack F Vogel /* ICH8 has opposite polarity of no_snoop bits. 52748cfa0ad2SJack F Vogel * By default, we should use snoop behavior. 52758cfa0ad2SJack F Vogel */ 52768cfa0ad2SJack F Vogel if (mac->type == e1000_ich8lan) 52778cfa0ad2SJack F Vogel snoop = PCIE_ICH8_SNOOP_ALL; 52788cfa0ad2SJack F Vogel else 52798cfa0ad2SJack F Vogel snoop = (u32) ~(PCIE_NO_SNOOP_ALL); 52808cfa0ad2SJack F Vogel e1000_set_pcie_no_snoop_generic(hw, snoop); 52818cfa0ad2SJack F Vogel 52828cfa0ad2SJack F Vogel ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); 52838cfa0ad2SJack F Vogel ctrl_ext |= E1000_CTRL_EXT_RO_DIS; 52848cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); 52858cfa0ad2SJack F Vogel 52866ab6bfe3SJack F Vogel /* Clear all of the statistics registers (clear on read). It is 52878cfa0ad2SJack F Vogel * important that we do this after we have tried to establish link 52888cfa0ad2SJack F Vogel * because the symbol error count will increment wildly if there 52898cfa0ad2SJack F Vogel * is no link. 52908cfa0ad2SJack F Vogel */ 52918cfa0ad2SJack F Vogel e1000_clear_hw_cntrs_ich8lan(hw); 52928cfa0ad2SJack F Vogel 52938cfa0ad2SJack F Vogel return ret_val; 52948cfa0ad2SJack F Vogel } 52956ab6bfe3SJack F Vogel 52968cfa0ad2SJack F Vogel /** 52978cfa0ad2SJack F Vogel * e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits 52988cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 52998cfa0ad2SJack F Vogel * 53008cfa0ad2SJack F Vogel * Sets/Clears required hardware bits necessary for correctly setting up the 53018cfa0ad2SJack F Vogel * hardware for transmit and receive. 53028cfa0ad2SJack F Vogel **/ 53038cfa0ad2SJack F Vogel static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw) 53048cfa0ad2SJack F Vogel { 53058cfa0ad2SJack F Vogel u32 reg; 53068cfa0ad2SJack F Vogel 53078cfa0ad2SJack F Vogel DEBUGFUNC("e1000_initialize_hw_bits_ich8lan"); 53088cfa0ad2SJack F Vogel 53098cfa0ad2SJack F Vogel /* Extended Device Control */ 53108cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_CTRL_EXT); 53118cfa0ad2SJack F Vogel reg |= (1 << 22); 53129d81738fSJack F Vogel /* Enable PHY low-power state when MAC is at D3 w/o WoL */ 53139d81738fSJack F Vogel if (hw->mac.type >= e1000_pchlan) 53149d81738fSJack F Vogel reg |= E1000_CTRL_EXT_PHYPDEN; 53158cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg); 53168cfa0ad2SJack F Vogel 53178cfa0ad2SJack F Vogel /* Transmit Descriptor Control 0 */ 53188cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_TXDCTL(0)); 53198cfa0ad2SJack F Vogel reg |= (1 << 22); 53208cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg); 53218cfa0ad2SJack F Vogel 53228cfa0ad2SJack F Vogel /* Transmit Descriptor Control 1 */ 53238cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_TXDCTL(1)); 53248cfa0ad2SJack F Vogel reg |= (1 << 22); 53258cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg); 53268cfa0ad2SJack F Vogel 53278cfa0ad2SJack F Vogel /* Transmit Arbitration Control 0 */ 53288cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_TARC(0)); 53298cfa0ad2SJack F Vogel if (hw->mac.type == e1000_ich8lan) 53308cfa0ad2SJack F Vogel reg |= (1 << 28) | (1 << 29); 53318cfa0ad2SJack F Vogel reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27); 53328cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TARC(0), reg); 53338cfa0ad2SJack F Vogel 53348cfa0ad2SJack F Vogel /* Transmit Arbitration Control 1 */ 53358cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_TARC(1)); 53368cfa0ad2SJack F Vogel if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR) 53378cfa0ad2SJack F Vogel reg &= ~(1 << 28); 53388cfa0ad2SJack F Vogel else 53398cfa0ad2SJack F Vogel reg |= (1 << 28); 53408cfa0ad2SJack F Vogel reg |= (1 << 24) | (1 << 26) | (1 << 30); 53418cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_TARC(1), reg); 53428cfa0ad2SJack F Vogel 53438cfa0ad2SJack F Vogel /* Device Status */ 53448cfa0ad2SJack F Vogel if (hw->mac.type == e1000_ich8lan) { 53458cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_STATUS); 53468f07d847SEitan Adler reg &= ~(1U << 31); 53478cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_STATUS, reg); 53488cfa0ad2SJack F Vogel } 53498cfa0ad2SJack F Vogel 53506ab6bfe3SJack F Vogel /* work-around descriptor data corruption issue during nfs v2 udp 53518ec87fc5SJack F Vogel * traffic, just disable the nfs filtering capability 53528ec87fc5SJack F Vogel */ 53538ec87fc5SJack F Vogel reg = E1000_READ_REG(hw, E1000_RFCTL); 53548ec87fc5SJack F Vogel reg |= (E1000_RFCTL_NFSW_DIS | E1000_RFCTL_NFSR_DIS); 53557609433eSJack F Vogel 53566ab6bfe3SJack F Vogel /* Disable IPv6 extension header parsing because some malformed 53576ab6bfe3SJack F Vogel * IPv6 headers can hang the Rx. 53586ab6bfe3SJack F Vogel */ 53596ab6bfe3SJack F Vogel if (hw->mac.type == e1000_ich8lan) 53606ab6bfe3SJack F Vogel reg |= (E1000_RFCTL_IPV6_EX_DIS | E1000_RFCTL_NEW_IPV6_EXT_DIS); 53618ec87fc5SJack F Vogel E1000_WRITE_REG(hw, E1000_RFCTL, reg); 53628ec87fc5SJack F Vogel 53636ab6bfe3SJack F Vogel /* Enable ECC on Lynxpoint */ 5364295df609SEric Joyner if (hw->mac.type >= e1000_pch_lpt) { 53656ab6bfe3SJack F Vogel reg = E1000_READ_REG(hw, E1000_PBECCSTS); 53666ab6bfe3SJack F Vogel reg |= E1000_PBECCSTS_ECC_ENABLE; 53676ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_PBECCSTS, reg); 53686ab6bfe3SJack F Vogel 53696ab6bfe3SJack F Vogel reg = E1000_READ_REG(hw, E1000_CTRL); 53706ab6bfe3SJack F Vogel reg |= E1000_CTRL_MEHE; 53716ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, reg); 53726ab6bfe3SJack F Vogel } 53736ab6bfe3SJack F Vogel 53748cfa0ad2SJack F Vogel return; 53758cfa0ad2SJack F Vogel } 53768cfa0ad2SJack F Vogel 53778cfa0ad2SJack F Vogel /** 53788cfa0ad2SJack F Vogel * e1000_setup_link_ich8lan - Setup flow control and link settings 53798cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 53808cfa0ad2SJack F Vogel * 53818cfa0ad2SJack F Vogel * Determines which flow control settings to use, then configures flow 53828cfa0ad2SJack F Vogel * control. Calls the appropriate media-specific link configuration 53838cfa0ad2SJack F Vogel * function. Assuming the adapter has a valid link partner, a valid link 53848cfa0ad2SJack F Vogel * should be established. Assumes the hardware has previously been reset 53858cfa0ad2SJack F Vogel * and the transmitter and receiver are not enabled. 53868cfa0ad2SJack F Vogel **/ 53878cfa0ad2SJack F Vogel static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw) 53888cfa0ad2SJack F Vogel { 53896ab6bfe3SJack F Vogel s32 ret_val; 53908cfa0ad2SJack F Vogel 53918cfa0ad2SJack F Vogel DEBUGFUNC("e1000_setup_link_ich8lan"); 53928cfa0ad2SJack F Vogel 53936ab6bfe3SJack F Vogel /* ICH parts do not have a word in the NVM to determine 53948cfa0ad2SJack F Vogel * the default flow control setting, so we explicitly 53958cfa0ad2SJack F Vogel * set it to full. 53968cfa0ad2SJack F Vogel */ 5397daf9197cSJack F Vogel if (hw->fc.requested_mode == e1000_fc_default) 5398daf9197cSJack F Vogel hw->fc.requested_mode = e1000_fc_full; 53998cfa0ad2SJack F Vogel 54006ab6bfe3SJack F Vogel /* Save off the requested flow control mode for use later. Depending 5401daf9197cSJack F Vogel * on the link partner's capabilities, we may or may not use this mode. 5402daf9197cSJack F Vogel */ 5403daf9197cSJack F Vogel hw->fc.current_mode = hw->fc.requested_mode; 54048cfa0ad2SJack F Vogel 5405daf9197cSJack F Vogel DEBUGOUT1("After fix-ups FlowControl is now = %x\n", 5406daf9197cSJack F Vogel hw->fc.current_mode); 54078cfa0ad2SJack F Vogel 540851569bd7SEric Joyner if (!hw->phy.ops.check_reset_block(hw)) { 54098cfa0ad2SJack F Vogel /* Continue to configure the copper link. */ 54108cfa0ad2SJack F Vogel ret_val = hw->mac.ops.setup_physical_interface(hw); 54118cfa0ad2SJack F Vogel if (ret_val) 54126ab6bfe3SJack F Vogel return ret_val; 541351569bd7SEric Joyner } 54148cfa0ad2SJack F Vogel 54158cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time); 54169d81738fSJack F Vogel if ((hw->phy.type == e1000_phy_82578) || 54177d9119bdSJack F Vogel (hw->phy.type == e1000_phy_82579) || 54186ab6bfe3SJack F Vogel (hw->phy.type == e1000_phy_i217) || 54199d81738fSJack F Vogel (hw->phy.type == e1000_phy_82577)) { 54207d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_FCRTV_PCH, hw->fc.refresh_time); 54217d9119bdSJack F Vogel 54229d81738fSJack F Vogel ret_val = hw->phy.ops.write_reg(hw, 54239d81738fSJack F Vogel PHY_REG(BM_PORT_CTRL_PAGE, 27), 54249d81738fSJack F Vogel hw->fc.pause_time); 54259d81738fSJack F Vogel if (ret_val) 54266ab6bfe3SJack F Vogel return ret_val; 54279d81738fSJack F Vogel } 54288cfa0ad2SJack F Vogel 54296ab6bfe3SJack F Vogel return e1000_set_fc_watermarks_generic(hw); 54308cfa0ad2SJack F Vogel } 54318cfa0ad2SJack F Vogel 54328cfa0ad2SJack F Vogel /** 54338cfa0ad2SJack F Vogel * e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface 54348cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 54358cfa0ad2SJack F Vogel * 54368cfa0ad2SJack F Vogel * Configures the kumeran interface to the PHY to wait the appropriate time 54378cfa0ad2SJack F Vogel * when polling the PHY, then call the generic setup_copper_link to finish 54388cfa0ad2SJack F Vogel * configuring the copper link. 54398cfa0ad2SJack F Vogel **/ 54408cfa0ad2SJack F Vogel static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw) 54418cfa0ad2SJack F Vogel { 54428cfa0ad2SJack F Vogel u32 ctrl; 54438cfa0ad2SJack F Vogel s32 ret_val; 54448cfa0ad2SJack F Vogel u16 reg_data; 54458cfa0ad2SJack F Vogel 54468cfa0ad2SJack F Vogel DEBUGFUNC("e1000_setup_copper_link_ich8lan"); 54478cfa0ad2SJack F Vogel 54488cfa0ad2SJack F Vogel ctrl = E1000_READ_REG(hw, E1000_CTRL); 54498cfa0ad2SJack F Vogel ctrl |= E1000_CTRL_SLU; 54508cfa0ad2SJack F Vogel ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); 54518cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 54528cfa0ad2SJack F Vogel 54536ab6bfe3SJack F Vogel /* Set the mac to wait the maximum time between each iteration 54548cfa0ad2SJack F Vogel * and increase the max iterations when polling the phy; 54558cfa0ad2SJack F Vogel * this fixes erroneous timeouts at 10Mbps. 54568cfa0ad2SJack F Vogel */ 54574edd8523SJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_TIMEOUTS, 54588cfa0ad2SJack F Vogel 0xFFFF); 54598cfa0ad2SJack F Vogel if (ret_val) 54606ab6bfe3SJack F Vogel return ret_val; 54619d81738fSJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw, 54629d81738fSJack F Vogel E1000_KMRNCTRLSTA_INBAND_PARAM, 54638cfa0ad2SJack F Vogel ®_data); 54648cfa0ad2SJack F Vogel if (ret_val) 54656ab6bfe3SJack F Vogel return ret_val; 54668cfa0ad2SJack F Vogel reg_data |= 0x3F; 54679d81738fSJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 54689d81738fSJack F Vogel E1000_KMRNCTRLSTA_INBAND_PARAM, 54698cfa0ad2SJack F Vogel reg_data); 54708cfa0ad2SJack F Vogel if (ret_val) 54716ab6bfe3SJack F Vogel return ret_val; 54728cfa0ad2SJack F Vogel 5473d035aa2dSJack F Vogel switch (hw->phy.type) { 5474d035aa2dSJack F Vogel case e1000_phy_igp_3: 54758cfa0ad2SJack F Vogel ret_val = e1000_copper_link_setup_igp(hw); 54768cfa0ad2SJack F Vogel if (ret_val) 54776ab6bfe3SJack F Vogel return ret_val; 5478d035aa2dSJack F Vogel break; 5479d035aa2dSJack F Vogel case e1000_phy_bm: 54809d81738fSJack F Vogel case e1000_phy_82578: 54818cfa0ad2SJack F Vogel ret_val = e1000_copper_link_setup_m88(hw); 54828cfa0ad2SJack F Vogel if (ret_val) 54836ab6bfe3SJack F Vogel return ret_val; 5484d035aa2dSJack F Vogel break; 54859d81738fSJack F Vogel case e1000_phy_82577: 54867d9119bdSJack F Vogel case e1000_phy_82579: 54879d81738fSJack F Vogel ret_val = e1000_copper_link_setup_82577(hw); 54889d81738fSJack F Vogel if (ret_val) 54896ab6bfe3SJack F Vogel return ret_val; 54909d81738fSJack F Vogel break; 5491d035aa2dSJack F Vogel case e1000_phy_ife: 54928cfa0ad2SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, 54938cfa0ad2SJack F Vogel ®_data); 54948cfa0ad2SJack F Vogel if (ret_val) 54956ab6bfe3SJack F Vogel return ret_val; 54968cfa0ad2SJack F Vogel 54978cfa0ad2SJack F Vogel reg_data &= ~IFE_PMC_AUTO_MDIX; 54988cfa0ad2SJack F Vogel 54998cfa0ad2SJack F Vogel switch (hw->phy.mdix) { 55008cfa0ad2SJack F Vogel case 1: 55018cfa0ad2SJack F Vogel reg_data &= ~IFE_PMC_FORCE_MDIX; 55028cfa0ad2SJack F Vogel break; 55038cfa0ad2SJack F Vogel case 2: 55048cfa0ad2SJack F Vogel reg_data |= IFE_PMC_FORCE_MDIX; 55058cfa0ad2SJack F Vogel break; 55068cfa0ad2SJack F Vogel case 0: 55078cfa0ad2SJack F Vogel default: 55088cfa0ad2SJack F Vogel reg_data |= IFE_PMC_AUTO_MDIX; 55098cfa0ad2SJack F Vogel break; 55108cfa0ad2SJack F Vogel } 55118cfa0ad2SJack F Vogel ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, 55128cfa0ad2SJack F Vogel reg_data); 55138cfa0ad2SJack F Vogel if (ret_val) 55146ab6bfe3SJack F Vogel return ret_val; 5515d035aa2dSJack F Vogel break; 5516d035aa2dSJack F Vogel default: 5517d035aa2dSJack F Vogel break; 55188cfa0ad2SJack F Vogel } 55198cfa0ad2SJack F Vogel 55206ab6bfe3SJack F Vogel return e1000_setup_copper_link_generic(hw); 55216ab6bfe3SJack F Vogel } 55226ab6bfe3SJack F Vogel 55236ab6bfe3SJack F Vogel /** 55246ab6bfe3SJack F Vogel * e1000_setup_copper_link_pch_lpt - Configure MAC/PHY interface 55256ab6bfe3SJack F Vogel * @hw: pointer to the HW structure 55266ab6bfe3SJack F Vogel * 55276ab6bfe3SJack F Vogel * Calls the PHY specific link setup function and then calls the 55286ab6bfe3SJack F Vogel * generic setup_copper_link to finish configuring the link for 55296ab6bfe3SJack F Vogel * Lynxpoint PCH devices 55306ab6bfe3SJack F Vogel **/ 55316ab6bfe3SJack F Vogel static s32 e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw) 55326ab6bfe3SJack F Vogel { 55336ab6bfe3SJack F Vogel u32 ctrl; 55346ab6bfe3SJack F Vogel s32 ret_val; 55356ab6bfe3SJack F Vogel 55366ab6bfe3SJack F Vogel DEBUGFUNC("e1000_setup_copper_link_pch_lpt"); 55376ab6bfe3SJack F Vogel 55386ab6bfe3SJack F Vogel ctrl = E1000_READ_REG(hw, E1000_CTRL); 55396ab6bfe3SJack F Vogel ctrl |= E1000_CTRL_SLU; 55406ab6bfe3SJack F Vogel ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); 55416ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, ctrl); 55426ab6bfe3SJack F Vogel 55436ab6bfe3SJack F Vogel ret_val = e1000_copper_link_setup_82577(hw); 55446ab6bfe3SJack F Vogel if (ret_val) 55458cfa0ad2SJack F Vogel return ret_val; 55466ab6bfe3SJack F Vogel 55476ab6bfe3SJack F Vogel return e1000_setup_copper_link_generic(hw); 55488cfa0ad2SJack F Vogel } 55498cfa0ad2SJack F Vogel 55508cfa0ad2SJack F Vogel /** 55518cfa0ad2SJack F Vogel * e1000_get_link_up_info_ich8lan - Get current link speed and duplex 55528cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 55538cfa0ad2SJack F Vogel * @speed: pointer to store current link speed 55548cfa0ad2SJack F Vogel * @duplex: pointer to store the current link duplex 55558cfa0ad2SJack F Vogel * 55568cfa0ad2SJack F Vogel * Calls the generic get_speed_and_duplex to retrieve the current link 55578cfa0ad2SJack F Vogel * information and then calls the Kumeran lock loss workaround for links at 55588cfa0ad2SJack F Vogel * gigabit speeds. 55598cfa0ad2SJack F Vogel **/ 55608cfa0ad2SJack F Vogel static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed, 55618cfa0ad2SJack F Vogel u16 *duplex) 55628cfa0ad2SJack F Vogel { 55638cfa0ad2SJack F Vogel s32 ret_val; 55648cfa0ad2SJack F Vogel 55658cfa0ad2SJack F Vogel DEBUGFUNC("e1000_get_link_up_info_ich8lan"); 55668cfa0ad2SJack F Vogel 55678cfa0ad2SJack F Vogel ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex); 55688cfa0ad2SJack F Vogel if (ret_val) 55696ab6bfe3SJack F Vogel return ret_val; 55708cfa0ad2SJack F Vogel 55718cfa0ad2SJack F Vogel if ((hw->mac.type == e1000_ich8lan) && 55728cfa0ad2SJack F Vogel (hw->phy.type == e1000_phy_igp_3) && 55738cfa0ad2SJack F Vogel (*speed == SPEED_1000)) { 55748cfa0ad2SJack F Vogel ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw); 55758cfa0ad2SJack F Vogel } 55768cfa0ad2SJack F Vogel 55778cfa0ad2SJack F Vogel return ret_val; 55788cfa0ad2SJack F Vogel } 55798cfa0ad2SJack F Vogel 55808cfa0ad2SJack F Vogel /** 55818cfa0ad2SJack F Vogel * e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround 55828cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 55838cfa0ad2SJack F Vogel * 55848cfa0ad2SJack F Vogel * Work-around for 82566 Kumeran PCS lock loss: 55858cfa0ad2SJack F Vogel * On link status change (i.e. PCI reset, speed change) and link is up and 55868cfa0ad2SJack F Vogel * speed is gigabit- 55878cfa0ad2SJack F Vogel * 0) if workaround is optionally disabled do nothing 55888cfa0ad2SJack F Vogel * 1) wait 1ms for Kumeran link to come up 55898cfa0ad2SJack F Vogel * 2) check Kumeran Diagnostic register PCS lock loss bit 55908cfa0ad2SJack F Vogel * 3) if not set the link is locked (all is good), otherwise... 55918cfa0ad2SJack F Vogel * 4) reset the PHY 55928cfa0ad2SJack F Vogel * 5) repeat up to 10 times 55938cfa0ad2SJack F Vogel * Note: this is only called for IGP3 copper when speed is 1gb. 55948cfa0ad2SJack F Vogel **/ 55958cfa0ad2SJack F Vogel static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw) 55968cfa0ad2SJack F Vogel { 5597daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 55988cfa0ad2SJack F Vogel u32 phy_ctrl; 55996ab6bfe3SJack F Vogel s32 ret_val; 56008cfa0ad2SJack F Vogel u16 i, data; 56018cfa0ad2SJack F Vogel bool link; 56028cfa0ad2SJack F Vogel 56038cfa0ad2SJack F Vogel DEBUGFUNC("e1000_kmrn_lock_loss_workaround_ich8lan"); 56048cfa0ad2SJack F Vogel 5605730d3130SJack F Vogel if (!dev_spec->kmrn_lock_loss_workaround_enabled) 56066ab6bfe3SJack F Vogel return E1000_SUCCESS; 56078cfa0ad2SJack F Vogel 56086ab6bfe3SJack F Vogel /* Make sure link is up before proceeding. If not just return. 56098cfa0ad2SJack F Vogel * Attempting this while link is negotiating fouled up link 56108cfa0ad2SJack F Vogel * stability 56118cfa0ad2SJack F Vogel */ 56128cfa0ad2SJack F Vogel ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); 56136ab6bfe3SJack F Vogel if (!link) 56146ab6bfe3SJack F Vogel return E1000_SUCCESS; 56158cfa0ad2SJack F Vogel 56168cfa0ad2SJack F Vogel for (i = 0; i < 10; i++) { 56178cfa0ad2SJack F Vogel /* read once to clear */ 56188cfa0ad2SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data); 56198cfa0ad2SJack F Vogel if (ret_val) 56206ab6bfe3SJack F Vogel return ret_val; 56218cfa0ad2SJack F Vogel /* and again to get new status */ 56228cfa0ad2SJack F Vogel ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data); 56238cfa0ad2SJack F Vogel if (ret_val) 56246ab6bfe3SJack F Vogel return ret_val; 56258cfa0ad2SJack F Vogel 56268cfa0ad2SJack F Vogel /* check for PCS lock */ 56276ab6bfe3SJack F Vogel if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) 56286ab6bfe3SJack F Vogel return E1000_SUCCESS; 56298cfa0ad2SJack F Vogel 56308cfa0ad2SJack F Vogel /* Issue PHY reset */ 56318cfa0ad2SJack F Vogel hw->phy.ops.reset(hw); 56328cfa0ad2SJack F Vogel msec_delay_irq(5); 56338cfa0ad2SJack F Vogel } 56348cfa0ad2SJack F Vogel /* Disable GigE link negotiation */ 56358cfa0ad2SJack F Vogel phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); 56368cfa0ad2SJack F Vogel phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE | 56378cfa0ad2SJack F Vogel E1000_PHY_CTRL_NOND0A_GBE_DISABLE); 56388cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 56398cfa0ad2SJack F Vogel 56406ab6bfe3SJack F Vogel /* Call gig speed drop workaround on Gig disable before accessing 56418cfa0ad2SJack F Vogel * any PHY registers 56428cfa0ad2SJack F Vogel */ 56438cfa0ad2SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw); 56448cfa0ad2SJack F Vogel 56458cfa0ad2SJack F Vogel /* unable to acquire PCS lock */ 56466ab6bfe3SJack F Vogel return -E1000_ERR_PHY; 56478cfa0ad2SJack F Vogel } 56488cfa0ad2SJack F Vogel 56498cfa0ad2SJack F Vogel /** 56508cfa0ad2SJack F Vogel * e1000_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state 56518cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 56528cfa0ad2SJack F Vogel * @state: boolean value used to set the current Kumeran workaround state 56538cfa0ad2SJack F Vogel * 56548cfa0ad2SJack F Vogel * If ICH8, set the current Kumeran workaround state (enabled - TRUE 56558cfa0ad2SJack F Vogel * /disabled - FALSE). 56568cfa0ad2SJack F Vogel **/ 56578cfa0ad2SJack F Vogel void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, 56588cfa0ad2SJack F Vogel bool state) 56598cfa0ad2SJack F Vogel { 5660daf9197cSJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 56618cfa0ad2SJack F Vogel 56628cfa0ad2SJack F Vogel DEBUGFUNC("e1000_set_kmrn_lock_loss_workaround_ich8lan"); 56638cfa0ad2SJack F Vogel 56648cfa0ad2SJack F Vogel if (hw->mac.type != e1000_ich8lan) { 56658cfa0ad2SJack F Vogel DEBUGOUT("Workaround applies to ICH8 only.\n"); 5666daf9197cSJack F Vogel return; 56678cfa0ad2SJack F Vogel } 56688cfa0ad2SJack F Vogel 56698cfa0ad2SJack F Vogel dev_spec->kmrn_lock_loss_workaround_enabled = state; 56708cfa0ad2SJack F Vogel 56718cfa0ad2SJack F Vogel return; 56728cfa0ad2SJack F Vogel } 56738cfa0ad2SJack F Vogel 56748cfa0ad2SJack F Vogel /** 56758cfa0ad2SJack F Vogel * e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3 56768cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 56778cfa0ad2SJack F Vogel * 56788cfa0ad2SJack F Vogel * Workaround for 82566 power-down on D3 entry: 56798cfa0ad2SJack F Vogel * 1) disable gigabit link 56808cfa0ad2SJack F Vogel * 2) write VR power-down enable 56818cfa0ad2SJack F Vogel * 3) read it back 56828cfa0ad2SJack F Vogel * Continue if successful, else issue LCD reset and repeat 56838cfa0ad2SJack F Vogel **/ 56848cfa0ad2SJack F Vogel void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw) 56858cfa0ad2SJack F Vogel { 56868cfa0ad2SJack F Vogel u32 reg; 56878cfa0ad2SJack F Vogel u16 data; 56888cfa0ad2SJack F Vogel u8 retry = 0; 56898cfa0ad2SJack F Vogel 56908cfa0ad2SJack F Vogel DEBUGFUNC("e1000_igp3_phy_powerdown_workaround_ich8lan"); 56918cfa0ad2SJack F Vogel 56928cfa0ad2SJack F Vogel if (hw->phy.type != e1000_phy_igp_3) 56936ab6bfe3SJack F Vogel return; 56948cfa0ad2SJack F Vogel 56958cfa0ad2SJack F Vogel /* Try the workaround twice (if needed) */ 56968cfa0ad2SJack F Vogel do { 56978cfa0ad2SJack F Vogel /* Disable link */ 56988cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_PHY_CTRL); 56998cfa0ad2SJack F Vogel reg |= (E1000_PHY_CTRL_GBE_DISABLE | 57008cfa0ad2SJack F Vogel E1000_PHY_CTRL_NOND0A_GBE_DISABLE); 57018cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, reg); 57028cfa0ad2SJack F Vogel 57036ab6bfe3SJack F Vogel /* Call gig speed drop workaround on Gig disable before 57048cfa0ad2SJack F Vogel * accessing any PHY registers 57058cfa0ad2SJack F Vogel */ 57068cfa0ad2SJack F Vogel if (hw->mac.type == e1000_ich8lan) 57078cfa0ad2SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw); 57088cfa0ad2SJack F Vogel 57098cfa0ad2SJack F Vogel /* Write VR power-down enable */ 57108cfa0ad2SJack F Vogel hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data); 57118cfa0ad2SJack F Vogel data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK; 5712daf9197cSJack F Vogel hw->phy.ops.write_reg(hw, IGP3_VR_CTRL, 57138cfa0ad2SJack F Vogel data | IGP3_VR_CTRL_MODE_SHUTDOWN); 57148cfa0ad2SJack F Vogel 57158cfa0ad2SJack F Vogel /* Read it back and test */ 57168cfa0ad2SJack F Vogel hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data); 57178cfa0ad2SJack F Vogel data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK; 57188cfa0ad2SJack F Vogel if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry) 57198cfa0ad2SJack F Vogel break; 57208cfa0ad2SJack F Vogel 57218cfa0ad2SJack F Vogel /* Issue PHY reset and repeat at most one more time */ 57228cfa0ad2SJack F Vogel reg = E1000_READ_REG(hw, E1000_CTRL); 57238cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_CTRL, reg | E1000_CTRL_PHY_RST); 57248cfa0ad2SJack F Vogel retry++; 57258cfa0ad2SJack F Vogel } while (retry); 57268cfa0ad2SJack F Vogel } 57278cfa0ad2SJack F Vogel 57288cfa0ad2SJack F Vogel /** 57298cfa0ad2SJack F Vogel * e1000_gig_downshift_workaround_ich8lan - WoL from S5 stops working 57308cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 57318cfa0ad2SJack F Vogel * 57328cfa0ad2SJack F Vogel * Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC), 57338cfa0ad2SJack F Vogel * LPLU, Gig disable, MDIC PHY reset): 57348cfa0ad2SJack F Vogel * 1) Set Kumeran Near-end loopback 57358cfa0ad2SJack F Vogel * 2) Clear Kumeran Near-end loopback 57364dab5c37SJack F Vogel * Should only be called for ICH8[m] devices with any 1G Phy. 57378cfa0ad2SJack F Vogel **/ 57388cfa0ad2SJack F Vogel void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw) 57398cfa0ad2SJack F Vogel { 57406ab6bfe3SJack F Vogel s32 ret_val; 5741*fc7682b1SKevin Bowling u16 reg_data = 0; 57428cfa0ad2SJack F Vogel 57438cfa0ad2SJack F Vogel DEBUGFUNC("e1000_gig_downshift_workaround_ich8lan"); 57448cfa0ad2SJack F Vogel 57458cfa0ad2SJack F Vogel if ((hw->mac.type != e1000_ich8lan) || 57464dab5c37SJack F Vogel (hw->phy.type == e1000_phy_ife)) 57476ab6bfe3SJack F Vogel return; 57488cfa0ad2SJack F Vogel 57498cfa0ad2SJack F Vogel ret_val = e1000_read_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, 57508cfa0ad2SJack F Vogel ®_data); 57518cfa0ad2SJack F Vogel if (ret_val) 57526ab6bfe3SJack F Vogel return; 57538cfa0ad2SJack F Vogel reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK; 57548cfa0ad2SJack F Vogel ret_val = e1000_write_kmrn_reg_generic(hw, 57558cfa0ad2SJack F Vogel E1000_KMRNCTRLSTA_DIAG_OFFSET, 57568cfa0ad2SJack F Vogel reg_data); 57578cfa0ad2SJack F Vogel if (ret_val) 57588cfa0ad2SJack F Vogel return; 57596ab6bfe3SJack F Vogel reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK; 57606ab6bfe3SJack F Vogel e1000_write_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, 57616ab6bfe3SJack F Vogel reg_data); 57628cfa0ad2SJack F Vogel } 57638cfa0ad2SJack F Vogel 57648cfa0ad2SJack F Vogel /** 57654dab5c37SJack F Vogel * e1000_suspend_workarounds_ich8lan - workarounds needed during S0->Sx 57668cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 57678cfa0ad2SJack F Vogel * 57688cfa0ad2SJack F Vogel * During S0 to Sx transition, it is possible the link remains at gig 57698cfa0ad2SJack F Vogel * instead of negotiating to a lower speed. Before going to Sx, set 57704dab5c37SJack F Vogel * 'Gig Disable' to force link speed negotiation to a lower speed based on 57714dab5c37SJack F Vogel * the LPLU setting in the NVM or custom setting. For PCH and newer parts, 57724dab5c37SJack F Vogel * the OEM bits PHY register (LED, GbE disable and LPLU configurations) also 57734dab5c37SJack F Vogel * needs to be written. 57746ab6bfe3SJack F Vogel * Parts that support (and are linked to a partner which support) EEE in 57756ab6bfe3SJack F Vogel * 100Mbps should disable LPLU since 100Mbps w/ EEE requires less power 57766ab6bfe3SJack F Vogel * than 10Mbps w/o EEE. 57778cfa0ad2SJack F Vogel **/ 57784dab5c37SJack F Vogel void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw) 57798cfa0ad2SJack F Vogel { 57806ab6bfe3SJack F Vogel struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 57818cfa0ad2SJack F Vogel u32 phy_ctrl; 57827d9119bdSJack F Vogel s32 ret_val; 57838cfa0ad2SJack F Vogel 57844dab5c37SJack F Vogel DEBUGFUNC("e1000_suspend_workarounds_ich8lan"); 57857d9119bdSJack F Vogel 57868cfa0ad2SJack F Vogel phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); 57874dab5c37SJack F Vogel phy_ctrl |= E1000_PHY_CTRL_GBE_DISABLE; 57886ab6bfe3SJack F Vogel 57896ab6bfe3SJack F Vogel if (hw->phy.type == e1000_phy_i217) { 57906ab6bfe3SJack F Vogel u16 phy_reg, device_id = hw->device_id; 57916ab6bfe3SJack F Vogel 57926ab6bfe3SJack F Vogel if ((device_id == E1000_DEV_ID_PCH_LPTLP_I218_LM) || 57938cc64f1eSJack F Vogel (device_id == E1000_DEV_ID_PCH_LPTLP_I218_V) || 57948cc64f1eSJack F Vogel (device_id == E1000_DEV_ID_PCH_I218_LM3) || 5795c80429ceSEric Joyner (device_id == E1000_DEV_ID_PCH_I218_V3) || 5796295df609SEric Joyner (hw->mac.type >= e1000_pch_spt)) { 57976ab6bfe3SJack F Vogel u32 fextnvm6 = E1000_READ_REG(hw, E1000_FEXTNVM6); 57986ab6bfe3SJack F Vogel 57996ab6bfe3SJack F Vogel E1000_WRITE_REG(hw, E1000_FEXTNVM6, 58006ab6bfe3SJack F Vogel fextnvm6 & ~E1000_FEXTNVM6_REQ_PLL_CLK); 58016ab6bfe3SJack F Vogel } 58026ab6bfe3SJack F Vogel 58036ab6bfe3SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 58046ab6bfe3SJack F Vogel if (ret_val) 58056ab6bfe3SJack F Vogel goto out; 58066ab6bfe3SJack F Vogel 58076ab6bfe3SJack F Vogel if (!dev_spec->eee_disable) { 58086ab6bfe3SJack F Vogel u16 eee_advert; 58096ab6bfe3SJack F Vogel 58106ab6bfe3SJack F Vogel ret_val = 58116ab6bfe3SJack F Vogel e1000_read_emi_reg_locked(hw, 58126ab6bfe3SJack F Vogel I217_EEE_ADVERTISEMENT, 58136ab6bfe3SJack F Vogel &eee_advert); 58146ab6bfe3SJack F Vogel if (ret_val) 58156ab6bfe3SJack F Vogel goto release; 58166ab6bfe3SJack F Vogel 58176ab6bfe3SJack F Vogel /* Disable LPLU if both link partners support 100BaseT 58186ab6bfe3SJack F Vogel * EEE and 100Full is advertised on both ends of the 58197609433eSJack F Vogel * link, and enable Auto Enable LPI since there will 58207609433eSJack F Vogel * be no driver to enable LPI while in Sx. 58216ab6bfe3SJack F Vogel */ 58226ab6bfe3SJack F Vogel if ((eee_advert & I82579_EEE_100_SUPPORTED) && 58236ab6bfe3SJack F Vogel (dev_spec->eee_lp_ability & 58246ab6bfe3SJack F Vogel I82579_EEE_100_SUPPORTED) && 58257609433eSJack F Vogel (hw->phy.autoneg_advertised & ADVERTISE_100_FULL)) { 58266ab6bfe3SJack F Vogel phy_ctrl &= ~(E1000_PHY_CTRL_D0A_LPLU | 58276ab6bfe3SJack F Vogel E1000_PHY_CTRL_NOND0A_LPLU); 58287609433eSJack F Vogel 58297609433eSJack F Vogel /* Set Auto Enable LPI after link up */ 58307609433eSJack F Vogel hw->phy.ops.read_reg_locked(hw, 58317609433eSJack F Vogel I217_LPI_GPIO_CTRL, 58327609433eSJack F Vogel &phy_reg); 58337609433eSJack F Vogel phy_reg |= I217_LPI_GPIO_CTRL_AUTO_EN_LPI; 58347609433eSJack F Vogel hw->phy.ops.write_reg_locked(hw, 58357609433eSJack F Vogel I217_LPI_GPIO_CTRL, 58367609433eSJack F Vogel phy_reg); 58377609433eSJack F Vogel } 58386ab6bfe3SJack F Vogel } 58396ab6bfe3SJack F Vogel 58406ab6bfe3SJack F Vogel /* For i217 Intel Rapid Start Technology support, 58416ab6bfe3SJack F Vogel * when the system is going into Sx and no manageability engine 58426ab6bfe3SJack F Vogel * is present, the driver must configure proxy to reset only on 58436ab6bfe3SJack F Vogel * power good. LPI (Low Power Idle) state must also reset only 58446ab6bfe3SJack F Vogel * on power good, as well as the MTA (Multicast table array). 58456ab6bfe3SJack F Vogel * The SMBus release must also be disabled on LCD reset. 58466ab6bfe3SJack F Vogel */ 58476ab6bfe3SJack F Vogel if (!(E1000_READ_REG(hw, E1000_FWSM) & 58486ab6bfe3SJack F Vogel E1000_ICH_FWSM_FW_VALID)) { 58496ab6bfe3SJack F Vogel /* Enable proxy to reset only on power good. */ 58506ab6bfe3SJack F Vogel hw->phy.ops.read_reg_locked(hw, I217_PROXY_CTRL, 58516ab6bfe3SJack F Vogel &phy_reg); 58526ab6bfe3SJack F Vogel phy_reg |= I217_PROXY_CTRL_AUTO_DISABLE; 58536ab6bfe3SJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_PROXY_CTRL, 58546ab6bfe3SJack F Vogel phy_reg); 58556ab6bfe3SJack F Vogel 58566ab6bfe3SJack F Vogel /* Set bit enable LPI (EEE) to reset only on 58576ab6bfe3SJack F Vogel * power good. 58586ab6bfe3SJack F Vogel */ 58596ab6bfe3SJack F Vogel hw->phy.ops.read_reg_locked(hw, I217_SxCTRL, &phy_reg); 58606ab6bfe3SJack F Vogel phy_reg |= I217_SxCTRL_ENABLE_LPI_RESET; 58616ab6bfe3SJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_SxCTRL, phy_reg); 58626ab6bfe3SJack F Vogel 58636ab6bfe3SJack F Vogel /* Disable the SMB release on LCD reset. */ 58646ab6bfe3SJack F Vogel hw->phy.ops.read_reg_locked(hw, I217_MEMPWR, &phy_reg); 58656ab6bfe3SJack F Vogel phy_reg &= ~I217_MEMPWR_DISABLE_SMB_RELEASE; 58666ab6bfe3SJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_MEMPWR, phy_reg); 58676ab6bfe3SJack F Vogel } 58686ab6bfe3SJack F Vogel 58696ab6bfe3SJack F Vogel /* Enable MTA to reset for Intel Rapid Start Technology 58706ab6bfe3SJack F Vogel * Support 58716ab6bfe3SJack F Vogel */ 58726ab6bfe3SJack F Vogel hw->phy.ops.read_reg_locked(hw, I217_CGFREG, &phy_reg); 58736ab6bfe3SJack F Vogel phy_reg |= I217_CGFREG_ENABLE_MTA_RESET; 58746ab6bfe3SJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_CGFREG, phy_reg); 58756ab6bfe3SJack F Vogel 58766ab6bfe3SJack F Vogel release: 58776ab6bfe3SJack F Vogel hw->phy.ops.release(hw); 58786ab6bfe3SJack F Vogel } 58796ab6bfe3SJack F Vogel out: 58808cfa0ad2SJack F Vogel E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); 58816ab6bfe3SJack F Vogel 58824dab5c37SJack F Vogel if (hw->mac.type == e1000_ich8lan) 58834dab5c37SJack F Vogel e1000_gig_downshift_workaround_ich8lan(hw); 58849d81738fSJack F Vogel 58857d9119bdSJack F Vogel if (hw->mac.type >= e1000_pchlan) { 58867d9119bdSJack F Vogel e1000_oem_bits_config_ich8lan(hw, FALSE); 58876ab6bfe3SJack F Vogel 58886ab6bfe3SJack F Vogel /* Reset PHY to activate OEM bits on 82577/8 */ 58896ab6bfe3SJack F Vogel if (hw->mac.type == e1000_pchlan) 58906ab6bfe3SJack F Vogel e1000_phy_hw_reset_generic(hw); 58916ab6bfe3SJack F Vogel 58927d9119bdSJack F Vogel ret_val = hw->phy.ops.acquire(hw); 58937d9119bdSJack F Vogel if (ret_val) 58947d9119bdSJack F Vogel return; 58957d9119bdSJack F Vogel e1000_write_smbus_addr(hw); 58967d9119bdSJack F Vogel hw->phy.ops.release(hw); 58978cfa0ad2SJack F Vogel } 58988cfa0ad2SJack F Vogel 58998cfa0ad2SJack F Vogel return; 59008cfa0ad2SJack F Vogel } 59018cfa0ad2SJack F Vogel 59028cfa0ad2SJack F Vogel /** 59034dab5c37SJack F Vogel * e1000_resume_workarounds_pchlan - workarounds needed during Sx->S0 59044dab5c37SJack F Vogel * @hw: pointer to the HW structure 59054dab5c37SJack F Vogel * 59064dab5c37SJack F Vogel * During Sx to S0 transitions on non-managed devices or managed devices 59074dab5c37SJack F Vogel * on which PHY resets are not blocked, if the PHY registers cannot be 59084dab5c37SJack F Vogel * accessed properly by the s/w toggle the LANPHYPC value to power cycle 59094dab5c37SJack F Vogel * the PHY. 59106ab6bfe3SJack F Vogel * On i217, setup Intel Rapid Start Technology. 59114dab5c37SJack F Vogel **/ 5912c80429ceSEric Joyner u32 e1000_resume_workarounds_pchlan(struct e1000_hw *hw) 59134dab5c37SJack F Vogel { 59144dab5c37SJack F Vogel s32 ret_val; 59154dab5c37SJack F Vogel 59164dab5c37SJack F Vogel DEBUGFUNC("e1000_resume_workarounds_pchlan"); 59176ab6bfe3SJack F Vogel if (hw->mac.type < e1000_pch2lan) 5918c80429ceSEric Joyner return E1000_SUCCESS; 59194dab5c37SJack F Vogel 59206ab6bfe3SJack F Vogel ret_val = e1000_init_phy_workarounds_pchlan(hw); 59214dab5c37SJack F Vogel if (ret_val) { 59226ab6bfe3SJack F Vogel DEBUGOUT1("Failed to init PHY flow ret_val=%d\n", ret_val); 5923c80429ceSEric Joyner return ret_val; 59244dab5c37SJack F Vogel } 59254dab5c37SJack F Vogel 59266ab6bfe3SJack F Vogel /* For i217 Intel Rapid Start Technology support when the system 59276ab6bfe3SJack F Vogel * is transitioning from Sx and no manageability engine is present 59286ab6bfe3SJack F Vogel * configure SMBus to restore on reset, disable proxy, and enable 59296ab6bfe3SJack F Vogel * the reset on MTA (Multicast table array). 59306ab6bfe3SJack F Vogel */ 59316ab6bfe3SJack F Vogel if (hw->phy.type == e1000_phy_i217) { 59326ab6bfe3SJack F Vogel u16 phy_reg; 59334dab5c37SJack F Vogel 59346ab6bfe3SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 59356ab6bfe3SJack F Vogel if (ret_val) { 59366ab6bfe3SJack F Vogel DEBUGOUT("Failed to setup iRST\n"); 5937c80429ceSEric Joyner return ret_val; 59386ab6bfe3SJack F Vogel } 59394dab5c37SJack F Vogel 59407609433eSJack F Vogel /* Clear Auto Enable LPI after link up */ 59417609433eSJack F Vogel hw->phy.ops.read_reg_locked(hw, I217_LPI_GPIO_CTRL, &phy_reg); 59427609433eSJack F Vogel phy_reg &= ~I217_LPI_GPIO_CTRL_AUTO_EN_LPI; 59437609433eSJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_LPI_GPIO_CTRL, phy_reg); 59447609433eSJack F Vogel 59456ab6bfe3SJack F Vogel if (!(E1000_READ_REG(hw, E1000_FWSM) & 59466ab6bfe3SJack F Vogel E1000_ICH_FWSM_FW_VALID)) { 59476ab6bfe3SJack F Vogel /* Restore clear on SMB if no manageability engine 59486ab6bfe3SJack F Vogel * is present 59496ab6bfe3SJack F Vogel */ 59506ab6bfe3SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, I217_MEMPWR, 59516ab6bfe3SJack F Vogel &phy_reg); 59526ab6bfe3SJack F Vogel if (ret_val) 59536ab6bfe3SJack F Vogel goto release; 59546ab6bfe3SJack F Vogel phy_reg |= I217_MEMPWR_DISABLE_SMB_RELEASE; 59556ab6bfe3SJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_MEMPWR, phy_reg); 59566ab6bfe3SJack F Vogel 59576ab6bfe3SJack F Vogel /* Disable Proxy */ 59586ab6bfe3SJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_PROXY_CTRL, 0); 59596ab6bfe3SJack F Vogel } 59606ab6bfe3SJack F Vogel /* Enable reset on MTA */ 59616ab6bfe3SJack F Vogel ret_val = hw->phy.ops.read_reg_locked(hw, I217_CGFREG, 59626ab6bfe3SJack F Vogel &phy_reg); 59636ab6bfe3SJack F Vogel if (ret_val) 59646ab6bfe3SJack F Vogel goto release; 59656ab6bfe3SJack F Vogel phy_reg &= ~I217_CGFREG_ENABLE_MTA_RESET; 59666ab6bfe3SJack F Vogel hw->phy.ops.write_reg_locked(hw, I217_CGFREG, phy_reg); 59674dab5c37SJack F Vogel release: 59686ab6bfe3SJack F Vogel if (ret_val) 59696ab6bfe3SJack F Vogel DEBUGOUT1("Error %d in resume workarounds\n", ret_val); 59704dab5c37SJack F Vogel hw->phy.ops.release(hw); 5971c80429ceSEric Joyner return ret_val; 59726ab6bfe3SJack F Vogel } 5973c80429ceSEric Joyner return E1000_SUCCESS; 59744dab5c37SJack F Vogel } 59754dab5c37SJack F Vogel 59764dab5c37SJack F Vogel /** 59778cfa0ad2SJack F Vogel * e1000_cleanup_led_ich8lan - Restore the default LED operation 59788cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 59798cfa0ad2SJack F Vogel * 59808cfa0ad2SJack F Vogel * Return the LED back to the default configuration. 59818cfa0ad2SJack F Vogel **/ 59828cfa0ad2SJack F Vogel static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw) 59838cfa0ad2SJack F Vogel { 59848cfa0ad2SJack F Vogel DEBUGFUNC("e1000_cleanup_led_ich8lan"); 59858cfa0ad2SJack F Vogel 59868cfa0ad2SJack F Vogel if (hw->phy.type == e1000_phy_ife) 5987a69ed8dfSJack F Vogel return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, 59888cfa0ad2SJack F Vogel 0); 59898cfa0ad2SJack F Vogel 5990a69ed8dfSJack F Vogel E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default); 5991a69ed8dfSJack F Vogel return E1000_SUCCESS; 59928cfa0ad2SJack F Vogel } 59938cfa0ad2SJack F Vogel 59948cfa0ad2SJack F Vogel /** 59958cfa0ad2SJack F Vogel * e1000_led_on_ich8lan - Turn LEDs on 59968cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 59978cfa0ad2SJack F Vogel * 59988cfa0ad2SJack F Vogel * Turn on the LEDs. 59998cfa0ad2SJack F Vogel **/ 60008cfa0ad2SJack F Vogel static s32 e1000_led_on_ich8lan(struct e1000_hw *hw) 60018cfa0ad2SJack F Vogel { 60028cfa0ad2SJack F Vogel DEBUGFUNC("e1000_led_on_ich8lan"); 60038cfa0ad2SJack F Vogel 60048cfa0ad2SJack F Vogel if (hw->phy.type == e1000_phy_ife) 6005a69ed8dfSJack F Vogel return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, 60068cfa0ad2SJack F Vogel (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON)); 60078cfa0ad2SJack F Vogel 6008a69ed8dfSJack F Vogel E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2); 6009a69ed8dfSJack F Vogel return E1000_SUCCESS; 60108cfa0ad2SJack F Vogel } 60118cfa0ad2SJack F Vogel 60128cfa0ad2SJack F Vogel /** 60138cfa0ad2SJack F Vogel * e1000_led_off_ich8lan - Turn LEDs off 60148cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 60158cfa0ad2SJack F Vogel * 60168cfa0ad2SJack F Vogel * Turn off the LEDs. 60178cfa0ad2SJack F Vogel **/ 60188cfa0ad2SJack F Vogel static s32 e1000_led_off_ich8lan(struct e1000_hw *hw) 60198cfa0ad2SJack F Vogel { 60208cfa0ad2SJack F Vogel DEBUGFUNC("e1000_led_off_ich8lan"); 60218cfa0ad2SJack F Vogel 60228cfa0ad2SJack F Vogel if (hw->phy.type == e1000_phy_ife) 6023a69ed8dfSJack F Vogel return hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, 60248cfa0ad2SJack F Vogel (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF)); 60258cfa0ad2SJack F Vogel 6026a69ed8dfSJack F Vogel E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1); 6027a69ed8dfSJack F Vogel return E1000_SUCCESS; 60288cfa0ad2SJack F Vogel } 60298cfa0ad2SJack F Vogel 60308cfa0ad2SJack F Vogel /** 60319d81738fSJack F Vogel * e1000_setup_led_pchlan - Configures SW controllable LED 60329d81738fSJack F Vogel * @hw: pointer to the HW structure 60339d81738fSJack F Vogel * 60349d81738fSJack F Vogel * This prepares the SW controllable LED for use. 60359d81738fSJack F Vogel **/ 60369d81738fSJack F Vogel static s32 e1000_setup_led_pchlan(struct e1000_hw *hw) 60379d81738fSJack F Vogel { 60389d81738fSJack F Vogel DEBUGFUNC("e1000_setup_led_pchlan"); 60399d81738fSJack F Vogel 60409d81738fSJack F Vogel return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, 60419d81738fSJack F Vogel (u16)hw->mac.ledctl_mode1); 60429d81738fSJack F Vogel } 60439d81738fSJack F Vogel 60449d81738fSJack F Vogel /** 60459d81738fSJack F Vogel * e1000_cleanup_led_pchlan - Restore the default LED operation 60469d81738fSJack F Vogel * @hw: pointer to the HW structure 60479d81738fSJack F Vogel * 60489d81738fSJack F Vogel * Return the LED back to the default configuration. 60499d81738fSJack F Vogel **/ 60509d81738fSJack F Vogel static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw) 60519d81738fSJack F Vogel { 60529d81738fSJack F Vogel DEBUGFUNC("e1000_cleanup_led_pchlan"); 60539d81738fSJack F Vogel 60549d81738fSJack F Vogel return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, 60559d81738fSJack F Vogel (u16)hw->mac.ledctl_default); 60569d81738fSJack F Vogel } 60579d81738fSJack F Vogel 60589d81738fSJack F Vogel /** 60599d81738fSJack F Vogel * e1000_led_on_pchlan - Turn LEDs on 60609d81738fSJack F Vogel * @hw: pointer to the HW structure 60619d81738fSJack F Vogel * 60629d81738fSJack F Vogel * Turn on the LEDs. 60639d81738fSJack F Vogel **/ 60649d81738fSJack F Vogel static s32 e1000_led_on_pchlan(struct e1000_hw *hw) 60659d81738fSJack F Vogel { 60669d81738fSJack F Vogel u16 data = (u16)hw->mac.ledctl_mode2; 60679d81738fSJack F Vogel u32 i, led; 60689d81738fSJack F Vogel 60699d81738fSJack F Vogel DEBUGFUNC("e1000_led_on_pchlan"); 60709d81738fSJack F Vogel 60716ab6bfe3SJack F Vogel /* If no link, then turn LED on by setting the invert bit 60729d81738fSJack F Vogel * for each LED that's mode is "link_up" in ledctl_mode2. 60739d81738fSJack F Vogel */ 60749d81738fSJack F Vogel if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) { 60759d81738fSJack F Vogel for (i = 0; i < 3; i++) { 60769d81738fSJack F Vogel led = (data >> (i * 5)) & E1000_PHY_LED0_MASK; 60779d81738fSJack F Vogel if ((led & E1000_PHY_LED0_MODE_MASK) != 60789d81738fSJack F Vogel E1000_LEDCTL_MODE_LINK_UP) 60799d81738fSJack F Vogel continue; 60809d81738fSJack F Vogel if (led & E1000_PHY_LED0_IVRT) 60819d81738fSJack F Vogel data &= ~(E1000_PHY_LED0_IVRT << (i * 5)); 60829d81738fSJack F Vogel else 60839d81738fSJack F Vogel data |= (E1000_PHY_LED0_IVRT << (i * 5)); 60849d81738fSJack F Vogel } 60859d81738fSJack F Vogel } 60869d81738fSJack F Vogel 60879d81738fSJack F Vogel return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data); 60889d81738fSJack F Vogel } 60899d81738fSJack F Vogel 60909d81738fSJack F Vogel /** 60919d81738fSJack F Vogel * e1000_led_off_pchlan - Turn LEDs off 60929d81738fSJack F Vogel * @hw: pointer to the HW structure 60939d81738fSJack F Vogel * 60949d81738fSJack F Vogel * Turn off the LEDs. 60959d81738fSJack F Vogel **/ 60969d81738fSJack F Vogel static s32 e1000_led_off_pchlan(struct e1000_hw *hw) 60979d81738fSJack F Vogel { 60989d81738fSJack F Vogel u16 data = (u16)hw->mac.ledctl_mode1; 60999d81738fSJack F Vogel u32 i, led; 61009d81738fSJack F Vogel 61019d81738fSJack F Vogel DEBUGFUNC("e1000_led_off_pchlan"); 61029d81738fSJack F Vogel 61036ab6bfe3SJack F Vogel /* If no link, then turn LED off by clearing the invert bit 61049d81738fSJack F Vogel * for each LED that's mode is "link_up" in ledctl_mode1. 61059d81738fSJack F Vogel */ 61069d81738fSJack F Vogel if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) { 61079d81738fSJack F Vogel for (i = 0; i < 3; i++) { 61089d81738fSJack F Vogel led = (data >> (i * 5)) & E1000_PHY_LED0_MASK; 61099d81738fSJack F Vogel if ((led & E1000_PHY_LED0_MODE_MASK) != 61109d81738fSJack F Vogel E1000_LEDCTL_MODE_LINK_UP) 61119d81738fSJack F Vogel continue; 61129d81738fSJack F Vogel if (led & E1000_PHY_LED0_IVRT) 61139d81738fSJack F Vogel data &= ~(E1000_PHY_LED0_IVRT << (i * 5)); 61149d81738fSJack F Vogel else 61159d81738fSJack F Vogel data |= (E1000_PHY_LED0_IVRT << (i * 5)); 61169d81738fSJack F Vogel } 61179d81738fSJack F Vogel } 61189d81738fSJack F Vogel 61199d81738fSJack F Vogel return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data); 61209d81738fSJack F Vogel } 61219d81738fSJack F Vogel 61229d81738fSJack F Vogel /** 61237d9119bdSJack F Vogel * e1000_get_cfg_done_ich8lan - Read config done bit after Full or PHY reset 61248cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 61258cfa0ad2SJack F Vogel * 61267d9119bdSJack F Vogel * Read appropriate register for the config done bit for completion status 61277d9119bdSJack F Vogel * and configure the PHY through s/w for EEPROM-less parts. 61287d9119bdSJack F Vogel * 61297d9119bdSJack F Vogel * NOTE: some silicon which is EEPROM-less will fail trying to read the 61307d9119bdSJack F Vogel * config done bit, so only an error is logged and continues. If we were 61317d9119bdSJack F Vogel * to return with error, EEPROM-less silicon would not be able to be reset 61327d9119bdSJack F Vogel * or change link. 61338cfa0ad2SJack F Vogel **/ 61348cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) 61358cfa0ad2SJack F Vogel { 61368cfa0ad2SJack F Vogel s32 ret_val = E1000_SUCCESS; 61378cfa0ad2SJack F Vogel u32 bank = 0; 61387d9119bdSJack F Vogel u32 status; 61398cfa0ad2SJack F Vogel 61407d9119bdSJack F Vogel DEBUGFUNC("e1000_get_cfg_done_ich8lan"); 61419d81738fSJack F Vogel 61428cfa0ad2SJack F Vogel e1000_get_cfg_done_generic(hw); 61438cfa0ad2SJack F Vogel 61447d9119bdSJack F Vogel /* Wait for indication from h/w that it has completed basic config */ 61457d9119bdSJack F Vogel if (hw->mac.type >= e1000_ich10lan) { 61467d9119bdSJack F Vogel e1000_lan_init_done_ich8lan(hw); 61477d9119bdSJack F Vogel } else { 61487d9119bdSJack F Vogel ret_val = e1000_get_auto_rd_done_generic(hw); 61497d9119bdSJack F Vogel if (ret_val) { 61506ab6bfe3SJack F Vogel /* When auto config read does not complete, do not 61517d9119bdSJack F Vogel * return with an error. This can happen in situations 61527d9119bdSJack F Vogel * where there is no eeprom and prevents getting link. 61537d9119bdSJack F Vogel */ 61547d9119bdSJack F Vogel DEBUGOUT("Auto Read Done did not complete\n"); 61557d9119bdSJack F Vogel ret_val = E1000_SUCCESS; 61567d9119bdSJack F Vogel } 61577d9119bdSJack F Vogel } 61587d9119bdSJack F Vogel 61597d9119bdSJack F Vogel /* Clear PHY Reset Asserted bit */ 61607d9119bdSJack F Vogel status = E1000_READ_REG(hw, E1000_STATUS); 61617d9119bdSJack F Vogel if (status & E1000_STATUS_PHYRA) 61627d9119bdSJack F Vogel E1000_WRITE_REG(hw, E1000_STATUS, status & ~E1000_STATUS_PHYRA); 61637d9119bdSJack F Vogel else 61647d9119bdSJack F Vogel DEBUGOUT("PHY Reset Asserted not set - needs delay\n"); 61657d9119bdSJack F Vogel 61668cfa0ad2SJack F Vogel /* If EEPROM is not marked present, init the IGP 3 PHY manually */ 61674edd8523SJack F Vogel if (hw->mac.type <= e1000_ich9lan) { 61686ab6bfe3SJack F Vogel if (!(E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) && 61698cfa0ad2SJack F Vogel (hw->phy.type == e1000_phy_igp_3)) { 61708cfa0ad2SJack F Vogel e1000_phy_init_script_igp3(hw); 61718cfa0ad2SJack F Vogel } 61728cfa0ad2SJack F Vogel } else { 61738cfa0ad2SJack F Vogel if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) { 6174daf9197cSJack F Vogel /* Maybe we should do a basic PHY config */ 61758cfa0ad2SJack F Vogel DEBUGOUT("EEPROM not present\n"); 61768cfa0ad2SJack F Vogel ret_val = -E1000_ERR_CONFIG; 61778cfa0ad2SJack F Vogel } 61788cfa0ad2SJack F Vogel } 61798cfa0ad2SJack F Vogel 61808cfa0ad2SJack F Vogel return ret_val; 61818cfa0ad2SJack F Vogel } 61828cfa0ad2SJack F Vogel 61838cfa0ad2SJack F Vogel /** 61848cfa0ad2SJack F Vogel * e1000_power_down_phy_copper_ich8lan - Remove link during PHY power down 61858cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 61868cfa0ad2SJack F Vogel * 61878cfa0ad2SJack F Vogel * In the case of a PHY power down to save power, or to turn off link during a 61888cfa0ad2SJack F Vogel * driver unload, or wake on lan is not enabled, remove the link. 61898cfa0ad2SJack F Vogel **/ 61908cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw) 61918cfa0ad2SJack F Vogel { 61928cfa0ad2SJack F Vogel /* If the management interface is not enabled, then power down */ 6193daf9197cSJack F Vogel if (!(hw->mac.ops.check_mng_mode(hw) || 6194daf9197cSJack F Vogel hw->phy.ops.check_reset_block(hw))) 61958cfa0ad2SJack F Vogel e1000_power_down_phy_copper(hw); 61968cfa0ad2SJack F Vogel 61978cfa0ad2SJack F Vogel return; 61988cfa0ad2SJack F Vogel } 61998cfa0ad2SJack F Vogel 62008cfa0ad2SJack F Vogel /** 62018cfa0ad2SJack F Vogel * e1000_clear_hw_cntrs_ich8lan - Clear statistical counters 62028cfa0ad2SJack F Vogel * @hw: pointer to the HW structure 62038cfa0ad2SJack F Vogel * 62048cfa0ad2SJack F Vogel * Clears hardware counters specific to the silicon family and calls 62058cfa0ad2SJack F Vogel * clear_hw_cntrs_generic to clear all general purpose counters. 62068cfa0ad2SJack F Vogel **/ 62078cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw) 62088cfa0ad2SJack F Vogel { 62099d81738fSJack F Vogel u16 phy_data; 62104dab5c37SJack F Vogel s32 ret_val; 62119d81738fSJack F Vogel 62128cfa0ad2SJack F Vogel DEBUGFUNC("e1000_clear_hw_cntrs_ich8lan"); 62138cfa0ad2SJack F Vogel 62148cfa0ad2SJack F Vogel e1000_clear_hw_cntrs_base_generic(hw); 62158cfa0ad2SJack F Vogel 6216daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_ALGNERRC); 6217daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_RXERRC); 6218daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_TNCRS); 6219daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_CEXTERR); 6220daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_TSCTC); 6221daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_TSCTFC); 62228cfa0ad2SJack F Vogel 6223daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_MGTPRC); 6224daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_MGTPDC); 6225daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_MGTPTC); 62268cfa0ad2SJack F Vogel 6227daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_IAC); 6228daf9197cSJack F Vogel E1000_READ_REG(hw, E1000_ICRXOC); 62299d81738fSJack F Vogel 62309d81738fSJack F Vogel /* Clear PHY statistics registers */ 62319d81738fSJack F Vogel if ((hw->phy.type == e1000_phy_82578) || 62327d9119bdSJack F Vogel (hw->phy.type == e1000_phy_82579) || 62336ab6bfe3SJack F Vogel (hw->phy.type == e1000_phy_i217) || 62349d81738fSJack F Vogel (hw->phy.type == e1000_phy_82577)) { 62354dab5c37SJack F Vogel ret_val = hw->phy.ops.acquire(hw); 62364dab5c37SJack F Vogel if (ret_val) 62374dab5c37SJack F Vogel return; 62384dab5c37SJack F Vogel ret_val = hw->phy.ops.set_page(hw, 62394dab5c37SJack F Vogel HV_STATS_PAGE << IGP_PAGE_SHIFT); 62404dab5c37SJack F Vogel if (ret_val) 62414dab5c37SJack F Vogel goto release; 62424dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_SCC_UPPER, &phy_data); 62434dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_SCC_LOWER, &phy_data); 62444dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_ECOL_UPPER, &phy_data); 62454dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_ECOL_LOWER, &phy_data); 62464dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_MCC_UPPER, &phy_data); 62474dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_MCC_LOWER, &phy_data); 62484dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_LATECOL_UPPER, &phy_data); 62494dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_LATECOL_LOWER, &phy_data); 62504dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_COLC_UPPER, &phy_data); 62514dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_COLC_LOWER, &phy_data); 62524dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_DC_UPPER, &phy_data); 62534dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_DC_LOWER, &phy_data); 62544dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_TNCRS_UPPER, &phy_data); 62554dab5c37SJack F Vogel hw->phy.ops.read_reg_page(hw, HV_TNCRS_LOWER, &phy_data); 62564dab5c37SJack F Vogel release: 62574dab5c37SJack F Vogel hw->phy.ops.release(hw); 62589d81738fSJack F Vogel } 62598cfa0ad2SJack F Vogel } 62608cfa0ad2SJack F Vogel 6261*fc7682b1SKevin Bowling /** 6262*fc7682b1SKevin Bowling * e1000_configure_k0s_lpt - Configure K0s power state 6263*fc7682b1SKevin Bowling * @hw: pointer to the HW structure 6264*fc7682b1SKevin Bowling * @entry_latency: Tx idle period for entering K0s - valid values are 0 to 3. 6265*fc7682b1SKevin Bowling * 0 corresponds to 128ns, each value over 0 doubles the duration. 6266*fc7682b1SKevin Bowling * @min_time: Minimum Tx idle period allowed - valid values are 0 to 4. 6267*fc7682b1SKevin Bowling * 0 corresponds to 128ns, each value over 0 doubles the duration. 6268*fc7682b1SKevin Bowling * 6269*fc7682b1SKevin Bowling * Configure the K1 power state based on the provided parameter. 6270*fc7682b1SKevin Bowling * Assumes semaphore already acquired. 6271*fc7682b1SKevin Bowling * 6272*fc7682b1SKevin Bowling * Success returns 0, Failure returns: 6273*fc7682b1SKevin Bowling * -E1000_ERR_PHY (-2) in case of access error 6274*fc7682b1SKevin Bowling * -E1000_ERR_PARAM (-4) in case of parameters error 6275*fc7682b1SKevin Bowling **/ 6276*fc7682b1SKevin Bowling s32 e1000_configure_k0s_lpt(struct e1000_hw *hw, u8 entry_latency, u8 min_time) 6277*fc7682b1SKevin Bowling { 6278*fc7682b1SKevin Bowling s32 ret_val; 6279*fc7682b1SKevin Bowling u16 kmrn_reg = 0; 6280*fc7682b1SKevin Bowling 6281*fc7682b1SKevin Bowling DEBUGFUNC("e1000_configure_k0s_lpt"); 6282*fc7682b1SKevin Bowling 6283*fc7682b1SKevin Bowling if (entry_latency > 3 || min_time > 4) 6284*fc7682b1SKevin Bowling return -E1000_ERR_PARAM; 6285*fc7682b1SKevin Bowling 6286*fc7682b1SKevin Bowling ret_val = e1000_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K0S_CTRL, 6287*fc7682b1SKevin Bowling &kmrn_reg); 6288*fc7682b1SKevin Bowling if (ret_val) 6289*fc7682b1SKevin Bowling return ret_val; 6290*fc7682b1SKevin Bowling 6291*fc7682b1SKevin Bowling /* for now don't touch the latency */ 6292*fc7682b1SKevin Bowling kmrn_reg &= ~(E1000_KMRNCTRLSTA_K0S_CTRL_MIN_TIME_MASK); 6293*fc7682b1SKevin Bowling kmrn_reg |= ((min_time << E1000_KMRNCTRLSTA_K0S_CTRL_MIN_TIME_SHIFT)); 6294*fc7682b1SKevin Bowling 6295*fc7682b1SKevin Bowling ret_val = e1000_write_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K0S_CTRL, 6296*fc7682b1SKevin Bowling kmrn_reg); 6297*fc7682b1SKevin Bowling if (ret_val) 6298*fc7682b1SKevin Bowling return ret_val; 6299*fc7682b1SKevin Bowling 6300*fc7682b1SKevin Bowling return E1000_SUCCESS; 6301*fc7682b1SKevin Bowling } 6302